puc.c revision 102734
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 102734 2002-08-31 20:29:46Z 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 8490731Sjhay#include <sys/param.h> 8590731Sjhay#include <sys/systm.h> 8690731Sjhay#include <sys/kernel.h> 8790731Sjhay#include <sys/bus.h> 8890731Sjhay#include <sys/conf.h> 8990731Sjhay#include <sys/malloc.h> 9090731Sjhay 9190731Sjhay#include <machine/bus.h> 9290731Sjhay#include <machine/resource.h> 9390731Sjhay#include <sys/rman.h> 9490731Sjhay 9590731Sjhay#include <dev/pci/pcireg.h> 9690731Sjhay#include <dev/pci/pcivar.h> 97102714Sphk 98102714Sphk#define PUC_ENTRAILS 1 9990731Sjhay#include <dev/puc/pucvar.h> 10090731Sjhay 10190731Sjhay#include <opt_puc.h> 10290731Sjhay 10390731Sjhay 10490731Sjhaystruct puc_device { 10590731Sjhay struct resource_list resources; 10690731Sjhay u_int serialfreq; 10790731Sjhay}; 10890731Sjhay 10990731Sjhaystatic void puc_intr(void *arg); 11090731Sjhay 11190731Sjhaystatic int puc_find_free_unit(char *); 11290731Sjhay#ifdef PUC_DEBUG 11390731Sjhaystatic void puc_print_resource_list(struct resource_list *); 11490731Sjhay#endif 11590731Sjhay 116102734Sphkstatic int 117102734Sphkpuc_port_bar_index(struct puc_softc *sc, int bar) 118102734Sphk{ 119102734Sphk int i; 120102734Sphk 121102734Sphk for (i = 0; i < PUC_MAX_BAR; i += 1) { 122102734Sphk if (!sc->sc_bar_mappings[i].used) 123102734Sphk break; 124102734Sphk if (sc->sc_bar_mappings[i].bar == bar) 125102734Sphk return (i); 126102734Sphk } 127102734Sphk sc->sc_bar_mappings[i].bar = bar; 128102734Sphk sc->sc_bar_mappings[i].used = 1; 129102734Sphk return (i); 130102734Sphk} 131102734Sphk 132102714Sphkint 133102714Sphkpuc_attach(device_t dev, const struct puc_device_description *desc) 13490731Sjhay{ 13590731Sjhay char *typestr; 13690731Sjhay int bidx, childunit, i, irq_setup, rid; 13790731Sjhay struct puc_softc *sc; 13890731Sjhay struct puc_device *pdev; 13990731Sjhay struct resource *res; 14090731Sjhay struct resource_list_entry *rle; 14190731Sjhay 14290731Sjhay sc = (struct puc_softc *)device_get_softc(dev); 14390731Sjhay bzero(sc, sizeof(*sc)); 144102714Sphk sc->sc_desc = desc; 14590731Sjhay if (sc->sc_desc == NULL) 14690731Sjhay return (ENXIO); 14790731Sjhay 14890731Sjhay#ifdef PUC_DEBUG 14990731Sjhay bootverbose = 1; 15090731Sjhay 15190731Sjhay printf("puc: name: %s\n", sc->sc_desc->name); 15290731Sjhay#endif 15390731Sjhay rid = 0; 15490731Sjhay res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, 15590731Sjhay RF_ACTIVE | RF_SHAREABLE); 15690731Sjhay if (!res) 15790731Sjhay return (ENXIO); 15890731Sjhay 15990731Sjhay sc->irqres = res; 16090731Sjhay sc->irqrid = rid; 16190731Sjhay#ifdef PUC_FASTINTR 16290731Sjhay irq_setup = BUS_SETUP_INTR(device_get_parent(dev), dev, res, 16390731Sjhay INTR_TYPE_TTY | INTR_FAST, puc_intr, sc, &sc->intr_cookie); 16490731Sjhay#else 16590731Sjhay irq_setup = ENXIO; 16690731Sjhay#endif 16790731Sjhay if (irq_setup != 0) 16890731Sjhay irq_setup = BUS_SETUP_INTR(device_get_parent(dev), dev, res, 16990731Sjhay INTR_TYPE_TTY, puc_intr, sc, &sc->intr_cookie); 17090731Sjhay if (irq_setup != 0) 17190731Sjhay return (ENXIO); 17290731Sjhay 17390731Sjhay rid = 0; 17490731Sjhay for (i = 0; PUC_PORT_VALID(sc->sc_desc, i); i++) { 175102734Sphk if (i > 0 && rid == sc->sc_desc->ports[i].bar) 17690731Sjhay sc->barmuxed = 1; 17790731Sjhay rid = sc->sc_desc->ports[i].bar; 178102734Sphk bidx = puc_port_bar_index(sc, rid); 17990731Sjhay 18090731Sjhay if (sc->sc_bar_mappings[bidx].res != NULL) 18190731Sjhay continue; 18290731Sjhay res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 18390731Sjhay 0ul, ~0ul, 1, RF_ACTIVE); 18490731Sjhay if (res == NULL) { 18590731Sjhay printf("could not get resource\n"); 18690731Sjhay continue; 18790731Sjhay } 18890731Sjhay sc->sc_bar_mappings[bidx].res = res; 18990731Sjhay#ifdef PUC_DEBUG 190102734Sphk printf("port rid %d bst %x, start %x, end %x\n", rid, 19190731Sjhay (u_int)rman_get_bustag(res), (u_int)rman_get_start(res), 19290731Sjhay (u_int)rman_get_end(res)); 19390731Sjhay#endif 19490731Sjhay } 19590731Sjhay 196102734Sphk if (desc->init != NULL) { 197102734Sphk i = desc->init(sc); 198102734Sphk if (i != 0) 199102734Sphk return (i); 200102734Sphk } 20190731Sjhay 20290731Sjhay for (i = 0; PUC_PORT_VALID(sc->sc_desc, i); i++) { 20390731Sjhay rid = sc->sc_desc->ports[i].bar; 204102734Sphk bidx = puc_port_bar_index(sc, rid); 20590731Sjhay if (sc->sc_bar_mappings[bidx].res == NULL) 20690731Sjhay continue; 20790731Sjhay 20890731Sjhay switch (sc->sc_desc->ports[i].type) { 20990731Sjhay case PUC_PORT_TYPE_COM: 21090731Sjhay typestr = "sio"; 21190731Sjhay break; 21290731Sjhay default: 21390731Sjhay continue; 21490731Sjhay } 21590731Sjhay pdev = malloc(sizeof(struct puc_device), M_DEVBUF, 21690731Sjhay M_NOWAIT | M_ZERO); 21790731Sjhay if (!pdev) 21890731Sjhay continue; 21990731Sjhay resource_list_init(&pdev->resources); 22090731Sjhay 22190731Sjhay /* First fake up an IRQ resource. */ 22290731Sjhay resource_list_add(&pdev->resources, SYS_RES_IRQ, 0, 22390731Sjhay rman_get_start(sc->irqres), rman_get_end(sc->irqres), 22490731Sjhay rman_get_end(sc->irqres) - rman_get_start(sc->irqres) + 1); 22590731Sjhay rle = resource_list_find(&pdev->resources, SYS_RES_IRQ, 0); 22690731Sjhay rle->res = sc->irqres; 22790731Sjhay 22890731Sjhay /* Now fake an IOPORT resource */ 22990731Sjhay res = sc->sc_bar_mappings[bidx].res; 23090731Sjhay resource_list_add(&pdev->resources, SYS_RES_IOPORT, 0, 23190731Sjhay rman_get_start(res) + sc->sc_desc->ports[i].offset, 232102734Sphk rman_get_start(res) + sc->sc_desc->ports[i].offset + 8 - 1, 23390731Sjhay 8); 23490731Sjhay rle = resource_list_find(&pdev->resources, SYS_RES_IOPORT, 0); 23590731Sjhay 23690731Sjhay if (sc->barmuxed == 0) { 23790731Sjhay rle->res = sc->sc_bar_mappings[bidx].res; 23890731Sjhay } else { 23990731Sjhay rle->res = malloc(sizeof(struct resource), M_DEVBUF, 24090731Sjhay M_WAITOK | M_ZERO); 24190925Snyan if (rle->res == NULL) { 24290925Snyan free(pdev, M_DEVBUF); 24390731Sjhay return (ENOMEM); 24490925Snyan } 24590731Sjhay 24690731Sjhay rle->res->r_start = rman_get_start(res) + 24790731Sjhay sc->sc_desc->ports[i].offset; 24890731Sjhay rle->res->r_end = rle->res->r_start + 8 - 1; 24990731Sjhay rle->res->r_bustag = rman_get_bustag(res); 25090731Sjhay bus_space_subregion(rle->res->r_bustag, 25190731Sjhay rman_get_bushandle(res), 25290731Sjhay sc->sc_desc->ports[i].offset, 8, 25390731Sjhay &rle->res->r_bushandle); 25490731Sjhay } 25590731Sjhay 25690731Sjhay pdev->serialfreq = sc->sc_desc->ports[i].serialfreq; 25790731Sjhay 25890731Sjhay childunit = puc_find_free_unit(typestr); 25990731Sjhay sc->sc_ports[i].dev = device_add_child(dev, typestr, childunit); 26090925Snyan if (sc->sc_ports[i].dev == NULL) { 26190925Snyan if (sc->barmuxed) { 26290925Snyan bus_space_unmap(rman_get_bustag(rle->res), 26390925Snyan rman_get_bushandle(rle->res), 26490925Snyan 8); 26590925Snyan free(rle->res, M_DEVBUF); 26690925Snyan free(pdev, M_DEVBUF); 26790925Snyan } 26890731Sjhay continue; 26990925Snyan } 27090731Sjhay device_set_ivars(sc->sc_ports[i].dev, pdev); 27190731Sjhay device_set_desc(sc->sc_ports[i].dev, sc->sc_desc->name); 27290731Sjhay if (!bootverbose) 27390731Sjhay device_quiet(sc->sc_ports[i].dev); 27490731Sjhay#ifdef PUC_DEBUG 27590731Sjhay printf("puc: type %d, bar %x, offset %x\n", 27690731Sjhay sc->sc_desc->ports[i].type, 27790731Sjhay sc->sc_desc->ports[i].bar, 27890731Sjhay sc->sc_desc->ports[i].offset); 279102714Sphk puc_print_resource_list(&pdev->resources); 28090731Sjhay#endif 28190925Snyan if (device_probe_and_attach(sc->sc_ports[i].dev) != 0) { 28290925Snyan if (sc->barmuxed) { 28390925Snyan bus_space_unmap(rman_get_bustag(rle->res), 28490925Snyan rman_get_bushandle(rle->res), 28590925Snyan 8); 28690925Snyan free(rle->res, M_DEVBUF); 28790925Snyan free(pdev, M_DEVBUF); 28890925Snyan } 28990925Snyan } 29090731Sjhay } 29190731Sjhay 29290731Sjhay#ifdef PUC_DEBUG 29390731Sjhay bootverbose = 0; 29490731Sjhay#endif 29590731Sjhay return (0); 29690731Sjhay} 29790731Sjhay 29890731Sjhay/* 29990731Sjhay * This is just an brute force interrupt handler. It just calls all the 30090731Sjhay * registered handlers sequencially. 30190731Sjhay * 30290731Sjhay * Later on we should maybe have a different handler for boards that can 30390731Sjhay * tell us which device generated the interrupt. 30490731Sjhay */ 30590731Sjhaystatic void 30690731Sjhaypuc_intr(void *arg) 30790731Sjhay{ 30890731Sjhay int i; 30990731Sjhay struct puc_softc *sc; 31090731Sjhay 311102734Sphkprintf("puc_intr\n"); 31290731Sjhay sc = (struct puc_softc *)arg; 31390731Sjhay for (i = 0; i < PUC_MAX_PORTS; i++) 31490731Sjhay if (sc->sc_ports[i].ihand != NULL) 31590731Sjhay (sc->sc_ports[i].ihand)(sc->sc_ports[i].ihandarg); 31690731Sjhay} 31790731Sjhay 318102714Sphkconst struct puc_device_description * 31990731Sjhaypuc_find_description(uint32_t vend, uint32_t prod, uint32_t svend, 32090731Sjhay uint32_t sprod) 32190731Sjhay{ 32290731Sjhay int i; 32390731Sjhay 32490731Sjhay#define checkreg(val, index) \ 32590731Sjhay (((val) & puc_devices[i].rmask[(index)]) == puc_devices[i].rval[(index)]) 32690731Sjhay 32790731Sjhay for (i = 0; puc_devices[i].name != NULL; i++) { 32890731Sjhay if (checkreg(vend, PUC_REG_VEND) && 32990731Sjhay checkreg(prod, PUC_REG_PROD) && 33090731Sjhay checkreg(svend, PUC_REG_SVEND) && 33190731Sjhay checkreg(sprod, PUC_REG_SPROD)) 33290731Sjhay return (&puc_devices[i]); 33390731Sjhay } 33490731Sjhay 33590731Sjhay#undef checkreg 33690731Sjhay 33790731Sjhay return (NULL); 33890731Sjhay} 33990731Sjhaystatic int puc_find_free_unit(char *name) 34090731Sjhay{ 34190731Sjhay devclass_t dc; 34290731Sjhay int start; 34390731Sjhay int unit; 34490731Sjhay 34590731Sjhay unit = 0; 34690731Sjhay start = 0; 34790731Sjhay while (resource_int_value(name, unit, "port", &start) == 0 && 34890731Sjhay start > 0) 34990731Sjhay unit++; 35090731Sjhay dc = devclass_find(name); 35190731Sjhay if (dc == NULL) 35290731Sjhay return (-1); 35390731Sjhay while (devclass_get_device(dc, unit)) 35490731Sjhay unit++; 35590731Sjhay#ifdef PUC_DEBUG 35690731Sjhay printf("puc: Using %s%d\n", name, unit); 35790731Sjhay#endif 35890731Sjhay return (unit); 35990731Sjhay} 36090731Sjhay 36190731Sjhay#ifdef PUC_DEBUG 36290731Sjhaystatic void 36390731Sjhaypuc_print_resource_list(struct resource_list *rl) 36490731Sjhay{ 365102734Sphk#if 0 36690731Sjhay struct resource_list_entry *rle; 36790731Sjhay 36890731Sjhay printf("print_resource_list: rl %p\n", rl); 36990731Sjhay SLIST_FOREACH(rle, rl, link) 370102734Sphk printf(" type %x, rid %x start %x end %x count %x\n", 371102734Sphk rle->type, rle->rid, rle->start, rle->end, rle->count); 37290731Sjhay printf("print_resource_list: end.\n"); 373102734Sphk#endif 37490731Sjhay} 37590731Sjhay#endif 37690731Sjhay 377102714Sphkstruct resource * 37890731Sjhaypuc_alloc_resource(device_t dev, device_t child, int type, int *rid, 37990731Sjhay u_long start, u_long end, u_long count, u_int flags) 38090731Sjhay{ 38190731Sjhay struct puc_device *pdev; 38290731Sjhay struct resource *retval; 38390731Sjhay struct resource_list *rl; 38490731Sjhay struct resource_list_entry *rle; 38590731Sjhay 38690731Sjhay pdev = device_get_ivars(child); 38790731Sjhay rl = &pdev->resources; 38890731Sjhay 38990731Sjhay#ifdef PUC_DEBUG 39090731Sjhay printf("puc_alloc_resource: pdev %p, looking for t %x, r %x\n", 39190731Sjhay pdev, type, *rid); 39290731Sjhay puc_print_resource_list(rl); 39390731Sjhay#endif 39490731Sjhay retval = NULL; 39590731Sjhay rle = resource_list_find(rl, type, *rid); 39690731Sjhay if (rle) { 39790731Sjhay start = rle->start; 39890731Sjhay end = rle->end; 39990731Sjhay count = rle->count; 40090731Sjhay#ifdef PUC_DEBUG 40190731Sjhay printf("found rle, %lx, %lx, %lx\n", start, end, count); 40290731Sjhay#endif 40390731Sjhay retval = rle->res; 40490731Sjhay } else 40590731Sjhay printf("oops rle is gone\n"); 40690731Sjhay 40790731Sjhay return (retval); 40890731Sjhay} 40990731Sjhay 410102714Sphkint 41190731Sjhaypuc_release_resource(device_t dev, device_t child, int type, int rid, 41290731Sjhay struct resource *res) 41390731Sjhay{ 41490731Sjhay return (0); 41590731Sjhay} 41690731Sjhay 417102714Sphkint 41890731Sjhaypuc_get_resource(device_t dev, device_t child, int type, int rid, 41990731Sjhay u_long *startp, u_long *countp) 42090731Sjhay{ 42190731Sjhay struct puc_device *pdev; 42290731Sjhay struct resource_list *rl; 42390731Sjhay struct resource_list_entry *rle; 42490731Sjhay 42590731Sjhay pdev = device_get_ivars(child); 42690731Sjhay rl = &pdev->resources; 42790731Sjhay 42890731Sjhay#ifdef PUC_DEBUG 42990731Sjhay printf("puc_get_resource: pdev %p, looking for t %x, r %x\n", pdev, 43090731Sjhay type, rid); 43190731Sjhay puc_print_resource_list(rl); 43290731Sjhay#endif 43390731Sjhay rle = resource_list_find(rl, type, rid); 43490731Sjhay if (rle) { 43590731Sjhay#ifdef PUC_DEBUG 43690731Sjhay printf("found rle %p,", rle); 43790731Sjhay#endif 43890731Sjhay if (startp != NULL) 43990731Sjhay *startp = rle->start; 44090731Sjhay if (countp != NULL) 44190731Sjhay *countp = rle->count; 44290731Sjhay#ifdef PUC_DEBUG 44390731Sjhay printf(" %lx, %lx\n", rle->start, rle->count); 44490731Sjhay#endif 44590731Sjhay return (0); 44690731Sjhay } else 44790731Sjhay printf("oops rle is gone\n"); 44890731Sjhay return (ENXIO); 44990731Sjhay} 45090731Sjhay 451102714Sphkint 45290731Sjhaypuc_setup_intr(device_t dev, device_t child, struct resource *r, int flags, 45390731Sjhay void (*ihand)(void *), void *arg, void **cookiep) 45490731Sjhay{ 45590731Sjhay int i; 45690731Sjhay struct puc_softc *sc; 45790731Sjhay 458102734Sphkprintf("puc_setup_intr()\n"); 45990731Sjhay sc = (struct puc_softc *)device_get_softc(dev); 46090731Sjhay for (i = 0; PUC_PORT_VALID(sc->sc_desc, i); i++) { 46190731Sjhay if (sc->sc_ports[i].dev == child) { 46290731Sjhay if (sc->sc_ports[i].ihand != 0) 46390731Sjhay return (ENXIO); 46490731Sjhay sc->sc_ports[i].ihand = ihand; 46590731Sjhay sc->sc_ports[i].ihandarg = arg; 46690731Sjhay *cookiep = arg; 46790731Sjhay return (0); 46890731Sjhay } 46990731Sjhay } 47090731Sjhay return (ENXIO); 47190731Sjhay} 47290731Sjhay 473102714Sphkint 47490731Sjhaypuc_teardown_intr(device_t dev, device_t child, struct resource *r, 47590731Sjhay void *cookie) 47690731Sjhay{ 47790731Sjhay int i; 47890731Sjhay struct puc_softc *sc; 47990731Sjhay 480102734Sphkprintf("puc_teardown_intr()\n"); 48190731Sjhay sc = (struct puc_softc *)device_get_softc(dev); 48290731Sjhay for (i = 0; PUC_PORT_VALID(sc->sc_desc, i); i++) { 48390731Sjhay if (sc->sc_ports[i].dev == child) { 48490731Sjhay sc->sc_ports[i].ihand = NULL; 48590731Sjhay sc->sc_ports[i].ihandarg = NULL; 48690731Sjhay return (0); 48790731Sjhay } 48890731Sjhay } 48990731Sjhay return (ENXIO); 49090731Sjhay} 49190731Sjhay 492102714Sphkint 49390731Sjhaypuc_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) 49490731Sjhay{ 49590731Sjhay struct puc_device *pdev; 49690731Sjhay 49790731Sjhay pdev = device_get_ivars(child); 49890731Sjhay if (pdev == NULL) 49990731Sjhay return (ENOENT); 50090731Sjhay 50190731Sjhay switch(index) { 50290731Sjhay case PUC_IVAR_FREQ: 50390731Sjhay *result = pdev->serialfreq; 50490731Sjhay break; 50590731Sjhay default: 50690731Sjhay return (ENOENT); 50790731Sjhay } 50890731Sjhay return (0); 50990731Sjhay} 51090731Sjhay 511102714Sphkdevclass_t puc_devclass; 51290731Sjhay 513