puc.c revision 104068
190731Sjhay/* $NetBSD: puc.c,v 1.7 2000/07/29 17:43:38 jlam Exp $ */ 290731Sjhay 390731Sjhay/*- 490731Sjhay * Copyright (c) 2002 JF Hay. All rights reserved. 590731Sjhay * Copyright (c) 2000 M. Warner Losh. All rights reserved. 690731Sjhay * 790731Sjhay * Redistribution and use in source and binary forms, with or without 890731Sjhay * modification, are permitted provided that the following conditions 990731Sjhay * are met: 1090731Sjhay * 1. Redistributions of source code must retain the above copyright 1190731Sjhay * notice unmodified, this list of conditions, and the following 1290731Sjhay * disclaimer. 1390731Sjhay * 2. Redistributions in binary form must reproduce the above copyright 1490731Sjhay * notice, this list of conditions and the following disclaimer in the 1590731Sjhay * documentation and/or other materials provided with the distribution. 1690731Sjhay * 1790731Sjhay * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1890731Sjhay * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1990731Sjhay * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2090731Sjhay * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2190731Sjhay * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2290731Sjhay * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2390731Sjhay * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2490731Sjhay * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2590731Sjhay * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2690731Sjhay * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2790731Sjhay */ 2890731Sjhay 2990731Sjhay/* 3090731Sjhay * Copyright (c) 1996, 1998, 1999 3190731Sjhay * Christopher G. Demetriou. All rights reserved. 3290731Sjhay * 3390731Sjhay * Redistribution and use in source and binary forms, with or without 3490731Sjhay * modification, are permitted provided that the following conditions 3590731Sjhay * are met: 3690731Sjhay * 1. Redistributions of source code must retain the above copyright 3790731Sjhay * notice, this list of conditions and the following disclaimer. 3890731Sjhay * 2. Redistributions in binary form must reproduce the above copyright 3990731Sjhay * notice, this list of conditions and the following disclaimer in the 4090731Sjhay * documentation and/or other materials provided with the distribution. 4190731Sjhay * 3. All advertising materials mentioning features or use of this software 4290731Sjhay * must display the following acknowledgement: 4390731Sjhay * This product includes software developed by Christopher G. Demetriou 4490731Sjhay * for the NetBSD Project. 4590731Sjhay * 4. The name of the author may not be used to endorse or promote products 4690731Sjhay * derived from this software without specific prior written permission 4790731Sjhay * 4890731Sjhay * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 4990731Sjhay * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 5090731Sjhay * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 5190731Sjhay * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 5290731Sjhay * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 5390731Sjhay * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 5490731Sjhay * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 5590731Sjhay * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 5690731Sjhay * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 5790731Sjhay * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 5890731Sjhay */ 5990731Sjhay 6090731Sjhay#include <sys/cdefs.h> 6190731Sjhay__FBSDID("$FreeBSD: head/sys/dev/puc/puc.c 104068 2002-09-27 22:01:32Z phk $"); 6290731Sjhay 6390731Sjhay/* 6490731Sjhay * PCI "universal" communication card device driver, glues com, lpt, 6590731Sjhay * and similar ports to PCI via bridge chip often much larger than 6690731Sjhay * the devices being glued. 6790731Sjhay * 6890731Sjhay * Author: Christopher G. Demetriou, May 14, 1998 (derived from NetBSD 6990731Sjhay * sys/dev/pci/pciide.c, revision 1.6). 7090731Sjhay * 7190731Sjhay * These devices could be (and some times are) described as 7290731Sjhay * communications/{serial,parallel}, etc. devices with known 7390731Sjhay * programming interfaces, but those programming interfaces (in 7490731Sjhay * particular the BAR assignments for devices, etc.) in fact are not 7590731Sjhay * particularly well defined. 7690731Sjhay * 7790731Sjhay * After I/we have seen more of these devices, it may be possible 7890731Sjhay * to generalize some of these bits. In particular, devices which 7990731Sjhay * describe themselves as communications/serial/16[45]50, and 8090731Sjhay * communications/parallel/??? might be attached via direct 8190731Sjhay * 'com' and 'lpt' attachments to pci. 8290731Sjhay */ 8390731Sjhay 84102751Sjmallett#include "opt_puc.h" 85102751Sjmallett 8690731Sjhay#include <sys/param.h> 8790731Sjhay#include <sys/systm.h> 8890731Sjhay#include <sys/kernel.h> 8990731Sjhay#include <sys/bus.h> 9090731Sjhay#include <sys/conf.h> 9190731Sjhay#include <sys/malloc.h> 9290731Sjhay 9390731Sjhay#include <machine/bus.h> 9490731Sjhay#include <machine/resource.h> 9590731Sjhay#include <sys/rman.h> 9690731Sjhay 9790731Sjhay#include <dev/pci/pcireg.h> 9890731Sjhay#include <dev/pci/pcivar.h> 99102714Sphk 100102714Sphk#define PUC_ENTRAILS 1 10190731Sjhay#include <dev/puc/pucvar.h> 10290731Sjhay 10390731Sjhaystruct puc_device { 10490731Sjhay struct resource_list resources; 10590731Sjhay u_int serialfreq; 10690731Sjhay}; 10790731Sjhay 10890731Sjhaystatic void puc_intr(void *arg); 10990731Sjhay 11090731Sjhaystatic int puc_find_free_unit(char *); 11190731Sjhay#ifdef PUC_DEBUG 11290731Sjhaystatic void puc_print_resource_list(struct resource_list *); 11390731Sjhay#endif 11490731Sjhay 115102893Sphkdevclass_t puc_devclass; 116102893Sphk 117102734Sphkstatic int 118102734Sphkpuc_port_bar_index(struct puc_softc *sc, int bar) 119102734Sphk{ 120102734Sphk int i; 121102734Sphk 122102734Sphk for (i = 0; i < PUC_MAX_BAR; i += 1) { 123102734Sphk if (!sc->sc_bar_mappings[i].used) 124102734Sphk break; 125102734Sphk if (sc->sc_bar_mappings[i].bar == bar) 126102734Sphk return (i); 127102734Sphk } 128102734Sphk sc->sc_bar_mappings[i].bar = bar; 129102734Sphk sc->sc_bar_mappings[i].used = 1; 130102734Sphk return (i); 131102734Sphk} 132102734Sphk 133102714Sphkint 134102714Sphkpuc_attach(device_t dev, const struct puc_device_description *desc) 13590731Sjhay{ 13690731Sjhay char *typestr; 13790731Sjhay int bidx, childunit, i, irq_setup, rid; 13890731Sjhay struct puc_softc *sc; 13990731Sjhay struct puc_device *pdev; 14090731Sjhay struct resource *res; 14190731Sjhay struct resource_list_entry *rle; 14290731Sjhay 14390731Sjhay sc = (struct puc_softc *)device_get_softc(dev); 14490731Sjhay bzero(sc, sizeof(*sc)); 145102714Sphk sc->sc_desc = desc; 14690731Sjhay if (sc->sc_desc == NULL) 14790731Sjhay return (ENXIO); 14890731Sjhay 14990731Sjhay#ifdef PUC_DEBUG 15090731Sjhay bootverbose = 1; 15190731Sjhay 15290731Sjhay printf("puc: name: %s\n", sc->sc_desc->name); 15390731Sjhay#endif 15490731Sjhay rid = 0; 15590731Sjhay res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, 15690731Sjhay RF_ACTIVE | RF_SHAREABLE); 15790731Sjhay if (!res) 15890731Sjhay return (ENXIO); 15990731Sjhay 16090731Sjhay sc->irqres = res; 16190731Sjhay sc->irqrid = rid; 162102929Sphk#ifdef PUC_FASTINTR 16390731Sjhay irq_setup = BUS_SETUP_INTR(device_get_parent(dev), dev, res, 164102929Sphk INTR_TYPE_TTY | INTR_FAST, puc_intr, sc, &sc->intr_cookie); 165102929Sphk if (irq_setup == 0) 166102931Sphk sc->fastintr = INTR_FAST; 167102929Sphk else 168102929Sphk irq_setup = BUS_SETUP_INTR(device_get_parent(dev), dev, res, 169102929Sphk INTR_TYPE_TTY, puc_intr, sc, &sc->intr_cookie); 170102929Sphk#else 171102929Sphk irq_setup = BUS_SETUP_INTR(device_get_parent(dev), dev, res, 172102895Sphk INTR_TYPE_TTY, puc_intr, sc, &sc->intr_cookie); 173102929Sphk#endif 17490731Sjhay if (irq_setup != 0) 17590731Sjhay return (ENXIO); 17690731Sjhay 17790731Sjhay rid = 0; 17890731Sjhay for (i = 0; PUC_PORT_VALID(sc->sc_desc, i); i++) { 179102734Sphk if (i > 0 && rid == sc->sc_desc->ports[i].bar) 18090731Sjhay sc->barmuxed = 1; 18190731Sjhay rid = sc->sc_desc->ports[i].bar; 182102734Sphk bidx = puc_port_bar_index(sc, rid); 18390731Sjhay 18490731Sjhay if (sc->sc_bar_mappings[bidx].res != NULL) 18590731Sjhay continue; 18690731Sjhay res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 18790731Sjhay 0ul, ~0ul, 1, RF_ACTIVE); 18890731Sjhay if (res == NULL) { 18990731Sjhay printf("could not get resource\n"); 19090731Sjhay continue; 19190731Sjhay } 19290731Sjhay sc->sc_bar_mappings[bidx].res = res; 19390731Sjhay#ifdef PUC_DEBUG 194102734Sphk printf("port rid %d bst %x, start %x, end %x\n", rid, 19590731Sjhay (u_int)rman_get_bustag(res), (u_int)rman_get_start(res), 19690731Sjhay (u_int)rman_get_end(res)); 19790731Sjhay#endif 19890731Sjhay } 19990731Sjhay 200102734Sphk if (desc->init != NULL) { 201102734Sphk i = desc->init(sc); 202102734Sphk if (i != 0) 203102734Sphk return (i); 204102734Sphk } 20590731Sjhay 20690731Sjhay for (i = 0; PUC_PORT_VALID(sc->sc_desc, i); i++) { 20790731Sjhay rid = sc->sc_desc->ports[i].bar; 208102734Sphk bidx = puc_port_bar_index(sc, rid); 20990731Sjhay if (sc->sc_bar_mappings[bidx].res == NULL) 21090731Sjhay continue; 21190731Sjhay 21290731Sjhay switch (sc->sc_desc->ports[i].type) { 21390731Sjhay case PUC_PORT_TYPE_COM: 21490731Sjhay typestr = "sio"; 21590731Sjhay break; 21690731Sjhay default: 21790731Sjhay continue; 21890731Sjhay } 21990731Sjhay pdev = malloc(sizeof(struct puc_device), M_DEVBUF, 22090731Sjhay M_NOWAIT | M_ZERO); 22190731Sjhay if (!pdev) 22290731Sjhay continue; 22390731Sjhay resource_list_init(&pdev->resources); 22490731Sjhay 22590731Sjhay /* First fake up an IRQ resource. */ 22690731Sjhay resource_list_add(&pdev->resources, SYS_RES_IRQ, 0, 22790731Sjhay rman_get_start(sc->irqres), rman_get_end(sc->irqres), 22890731Sjhay rman_get_end(sc->irqres) - rman_get_start(sc->irqres) + 1); 22990731Sjhay rle = resource_list_find(&pdev->resources, SYS_RES_IRQ, 0); 23090731Sjhay rle->res = sc->irqres; 23190731Sjhay 23290731Sjhay /* Now fake an IOPORT resource */ 23390731Sjhay res = sc->sc_bar_mappings[bidx].res; 23490731Sjhay resource_list_add(&pdev->resources, SYS_RES_IOPORT, 0, 23590731Sjhay rman_get_start(res) + sc->sc_desc->ports[i].offset, 236102734Sphk rman_get_start(res) + sc->sc_desc->ports[i].offset + 8 - 1, 23790731Sjhay 8); 23890731Sjhay rle = resource_list_find(&pdev->resources, SYS_RES_IOPORT, 0); 23990731Sjhay 24090731Sjhay if (sc->barmuxed == 0) { 24190731Sjhay rle->res = sc->sc_bar_mappings[bidx].res; 24290731Sjhay } else { 24390731Sjhay rle->res = malloc(sizeof(struct resource), M_DEVBUF, 24490731Sjhay M_WAITOK | M_ZERO); 24590925Snyan if (rle->res == NULL) { 24690925Snyan free(pdev, M_DEVBUF); 24790731Sjhay return (ENOMEM); 24890925Snyan } 24990731Sjhay 25090731Sjhay rle->res->r_start = rman_get_start(res) + 25190731Sjhay sc->sc_desc->ports[i].offset; 25290731Sjhay rle->res->r_end = rle->res->r_start + 8 - 1; 25390731Sjhay rle->res->r_bustag = rman_get_bustag(res); 25490731Sjhay bus_space_subregion(rle->res->r_bustag, 25590731Sjhay rman_get_bushandle(res), 25690731Sjhay sc->sc_desc->ports[i].offset, 8, 25790731Sjhay &rle->res->r_bushandle); 25890731Sjhay } 25990731Sjhay 26090731Sjhay pdev->serialfreq = sc->sc_desc->ports[i].serialfreq; 26190731Sjhay 26290731Sjhay childunit = puc_find_free_unit(typestr); 26390731Sjhay sc->sc_ports[i].dev = device_add_child(dev, typestr, childunit); 26490925Snyan if (sc->sc_ports[i].dev == NULL) { 26590925Snyan if (sc->barmuxed) { 26690925Snyan bus_space_unmap(rman_get_bustag(rle->res), 26790925Snyan rman_get_bushandle(rle->res), 26890925Snyan 8); 26990925Snyan free(rle->res, M_DEVBUF); 27090925Snyan free(pdev, M_DEVBUF); 27190925Snyan } 27290731Sjhay continue; 27390925Snyan } 27490731Sjhay device_set_ivars(sc->sc_ports[i].dev, pdev); 27590731Sjhay device_set_desc(sc->sc_ports[i].dev, sc->sc_desc->name); 27690731Sjhay if (!bootverbose) 27790731Sjhay device_quiet(sc->sc_ports[i].dev); 27890731Sjhay#ifdef PUC_DEBUG 27990731Sjhay printf("puc: type %d, bar %x, offset %x\n", 28090731Sjhay sc->sc_desc->ports[i].type, 28190731Sjhay sc->sc_desc->ports[i].bar, 28290731Sjhay sc->sc_desc->ports[i].offset); 283102714Sphk puc_print_resource_list(&pdev->resources); 28490731Sjhay#endif 285104068Sphk device_set_flags(sc->sc_ports[i].dev, 286104068Sphk sc->sc_desc->ports[i].flags); 28790925Snyan if (device_probe_and_attach(sc->sc_ports[i].dev) != 0) { 28890925Snyan if (sc->barmuxed) { 28990925Snyan bus_space_unmap(rman_get_bustag(rle->res), 29090925Snyan rman_get_bushandle(rle->res), 29190925Snyan 8); 29290925Snyan free(rle->res, M_DEVBUF); 29390925Snyan free(pdev, M_DEVBUF); 29490925Snyan } 29590925Snyan } 29690731Sjhay } 29790731Sjhay 29890731Sjhay#ifdef PUC_DEBUG 29990731Sjhay bootverbose = 0; 30090731Sjhay#endif 30190731Sjhay return (0); 30290731Sjhay} 30390731Sjhay 30490731Sjhay/* 30590731Sjhay * This is just an brute force interrupt handler. It just calls all the 30690731Sjhay * registered handlers sequencially. 30790731Sjhay * 30890731Sjhay * Later on we should maybe have a different handler for boards that can 30990731Sjhay * tell us which device generated the interrupt. 31090731Sjhay */ 31190731Sjhaystatic void 31290731Sjhaypuc_intr(void *arg) 31390731Sjhay{ 31490731Sjhay int i; 31590731Sjhay struct puc_softc *sc; 31690731Sjhay 31790731Sjhay sc = (struct puc_softc *)arg; 31890731Sjhay for (i = 0; i < PUC_MAX_PORTS; i++) 31990731Sjhay if (sc->sc_ports[i].ihand != NULL) 32090731Sjhay (sc->sc_ports[i].ihand)(sc->sc_ports[i].ihandarg); 32190731Sjhay} 32290731Sjhay 323102714Sphkconst struct puc_device_description * 32490731Sjhaypuc_find_description(uint32_t vend, uint32_t prod, uint32_t svend, 32590731Sjhay uint32_t sprod) 32690731Sjhay{ 32790731Sjhay int i; 32890731Sjhay 32990731Sjhay#define checkreg(val, index) \ 33090731Sjhay (((val) & puc_devices[i].rmask[(index)]) == puc_devices[i].rval[(index)]) 33190731Sjhay 33290731Sjhay for (i = 0; puc_devices[i].name != NULL; i++) { 33390731Sjhay if (checkreg(vend, PUC_REG_VEND) && 33490731Sjhay checkreg(prod, PUC_REG_PROD) && 33590731Sjhay checkreg(svend, PUC_REG_SVEND) && 33690731Sjhay checkreg(sprod, PUC_REG_SPROD)) 33790731Sjhay return (&puc_devices[i]); 33890731Sjhay } 33990731Sjhay 34090731Sjhay#undef checkreg 34190731Sjhay 34290731Sjhay return (NULL); 34390731Sjhay} 344102894Sphk 345102894Sphkstatic int 346102894Sphkpuc_find_free_unit(char *name) 34790731Sjhay{ 34890731Sjhay devclass_t dc; 34990731Sjhay int start; 35090731Sjhay int unit; 35190731Sjhay 35290731Sjhay unit = 0; 35390731Sjhay start = 0; 35490731Sjhay while (resource_int_value(name, unit, "port", &start) == 0 && 35590731Sjhay start > 0) 35690731Sjhay unit++; 35790731Sjhay dc = devclass_find(name); 35890731Sjhay if (dc == NULL) 35990731Sjhay return (-1); 36090731Sjhay while (devclass_get_device(dc, unit)) 36190731Sjhay unit++; 36290731Sjhay#ifdef PUC_DEBUG 36390731Sjhay printf("puc: Using %s%d\n", name, unit); 36490731Sjhay#endif 36590731Sjhay return (unit); 36690731Sjhay} 36790731Sjhay 36890731Sjhay#ifdef PUC_DEBUG 36990731Sjhaystatic void 37090731Sjhaypuc_print_resource_list(struct resource_list *rl) 37190731Sjhay{ 372102734Sphk#if 0 37390731Sjhay struct resource_list_entry *rle; 37490731Sjhay 37590731Sjhay printf("print_resource_list: rl %p\n", rl); 37690731Sjhay SLIST_FOREACH(rle, rl, link) 377102734Sphk printf(" type %x, rid %x start %x end %x count %x\n", 378102734Sphk rle->type, rle->rid, rle->start, rle->end, rle->count); 37990731Sjhay printf("print_resource_list: end.\n"); 380102734Sphk#endif 38190731Sjhay} 38290731Sjhay#endif 38390731Sjhay 384102714Sphkstruct resource * 38590731Sjhaypuc_alloc_resource(device_t dev, device_t child, int type, int *rid, 38690731Sjhay u_long start, u_long end, u_long count, u_int flags) 38790731Sjhay{ 38890731Sjhay struct puc_device *pdev; 38990731Sjhay struct resource *retval; 39090731Sjhay struct resource_list *rl; 39190731Sjhay struct resource_list_entry *rle; 39290731Sjhay 39390731Sjhay pdev = device_get_ivars(child); 39490731Sjhay rl = &pdev->resources; 39590731Sjhay 39690731Sjhay#ifdef PUC_DEBUG 39790731Sjhay printf("puc_alloc_resource: pdev %p, looking for t %x, r %x\n", 39890731Sjhay pdev, type, *rid); 39990731Sjhay puc_print_resource_list(rl); 40090731Sjhay#endif 40190731Sjhay retval = NULL; 40290731Sjhay rle = resource_list_find(rl, type, *rid); 40390731Sjhay if (rle) { 40490731Sjhay start = rle->start; 40590731Sjhay end = rle->end; 40690731Sjhay count = rle->count; 40790731Sjhay#ifdef PUC_DEBUG 40890731Sjhay printf("found rle, %lx, %lx, %lx\n", start, end, count); 40990731Sjhay#endif 41090731Sjhay retval = rle->res; 41190731Sjhay } else 41290731Sjhay printf("oops rle is gone\n"); 41390731Sjhay 41490731Sjhay return (retval); 41590731Sjhay} 41690731Sjhay 417102714Sphkint 41890731Sjhaypuc_release_resource(device_t dev, device_t child, int type, int rid, 41990731Sjhay struct resource *res) 42090731Sjhay{ 42190731Sjhay return (0); 42290731Sjhay} 42390731Sjhay 424102714Sphkint 42590731Sjhaypuc_get_resource(device_t dev, device_t child, int type, int rid, 42690731Sjhay u_long *startp, u_long *countp) 42790731Sjhay{ 42890731Sjhay struct puc_device *pdev; 42990731Sjhay struct resource_list *rl; 43090731Sjhay struct resource_list_entry *rle; 43190731Sjhay 43290731Sjhay pdev = device_get_ivars(child); 43390731Sjhay rl = &pdev->resources; 43490731Sjhay 43590731Sjhay#ifdef PUC_DEBUG 43690731Sjhay printf("puc_get_resource: pdev %p, looking for t %x, r %x\n", pdev, 43790731Sjhay type, rid); 43890731Sjhay puc_print_resource_list(rl); 43990731Sjhay#endif 44090731Sjhay rle = resource_list_find(rl, type, rid); 44190731Sjhay if (rle) { 44290731Sjhay#ifdef PUC_DEBUG 44390731Sjhay printf("found rle %p,", rle); 44490731Sjhay#endif 44590731Sjhay if (startp != NULL) 44690731Sjhay *startp = rle->start; 44790731Sjhay if (countp != NULL) 44890731Sjhay *countp = rle->count; 44990731Sjhay#ifdef PUC_DEBUG 45090731Sjhay printf(" %lx, %lx\n", rle->start, rle->count); 45190731Sjhay#endif 45290731Sjhay return (0); 45390731Sjhay } else 45490731Sjhay printf("oops rle is gone\n"); 45590731Sjhay return (ENXIO); 45690731Sjhay} 45790731Sjhay 458102714Sphkint 45990731Sjhaypuc_setup_intr(device_t dev, device_t child, struct resource *r, int flags, 46090731Sjhay void (*ihand)(void *), void *arg, void **cookiep) 46190731Sjhay{ 46290731Sjhay int i; 46390731Sjhay struct puc_softc *sc; 46490731Sjhay 465102929Sphk sc = (struct puc_softc *)device_get_softc(dev); 466102931Sphk if ((flags & INTR_FAST) != sc->fastintr) 467102895Sphk return (ENXIO); 46890731Sjhay for (i = 0; PUC_PORT_VALID(sc->sc_desc, i); i++) { 46990731Sjhay if (sc->sc_ports[i].dev == child) { 47090731Sjhay if (sc->sc_ports[i].ihand != 0) 47190731Sjhay return (ENXIO); 47290731Sjhay sc->sc_ports[i].ihand = ihand; 47390731Sjhay sc->sc_ports[i].ihandarg = arg; 47490731Sjhay *cookiep = arg; 47590731Sjhay return (0); 47690731Sjhay } 47790731Sjhay } 47890731Sjhay return (ENXIO); 47990731Sjhay} 48090731Sjhay 481102714Sphkint 48290731Sjhaypuc_teardown_intr(device_t dev, device_t child, struct resource *r, 48390731Sjhay void *cookie) 48490731Sjhay{ 48590731Sjhay int i; 48690731Sjhay struct puc_softc *sc; 48790731Sjhay 48890731Sjhay sc = (struct puc_softc *)device_get_softc(dev); 48990731Sjhay for (i = 0; PUC_PORT_VALID(sc->sc_desc, i); i++) { 49090731Sjhay if (sc->sc_ports[i].dev == child) { 49190731Sjhay sc->sc_ports[i].ihand = NULL; 49290731Sjhay sc->sc_ports[i].ihandarg = NULL; 49390731Sjhay return (0); 49490731Sjhay } 49590731Sjhay } 49690731Sjhay return (ENXIO); 49790731Sjhay} 49890731Sjhay 499102714Sphkint 50090731Sjhaypuc_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) 50190731Sjhay{ 50290731Sjhay struct puc_device *pdev; 50390731Sjhay 50490731Sjhay pdev = device_get_ivars(child); 50590731Sjhay if (pdev == NULL) 50690731Sjhay return (ENOENT); 50790731Sjhay 50890731Sjhay switch(index) { 50990731Sjhay case PUC_IVAR_FREQ: 51090731Sjhay *result = pdev->serialfreq; 51190731Sjhay break; 51290731Sjhay default: 51390731Sjhay return (ENOENT); 51490731Sjhay } 51590731Sjhay return (0); 51690731Sjhay} 517