puc.c revision 102894
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 102894 2002-09-03 11:19:44Z 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; 16290731Sjhay#ifdef PUC_FASTINTR 16390731Sjhay irq_setup = BUS_SETUP_INTR(device_get_parent(dev), dev, res, 16490731Sjhay INTR_TYPE_TTY | INTR_FAST, puc_intr, sc, &sc->intr_cookie); 16590731Sjhay#else 16690731Sjhay irq_setup = ENXIO; 16790731Sjhay#endif 16890731Sjhay if (irq_setup != 0) 16990731Sjhay irq_setup = BUS_SETUP_INTR(device_get_parent(dev), dev, res, 17090731Sjhay INTR_TYPE_TTY, puc_intr, sc, &sc->intr_cookie); 17190731Sjhay if (irq_setup != 0) 17290731Sjhay return (ENXIO); 17390731Sjhay 17490731Sjhay rid = 0; 17590731Sjhay for (i = 0; PUC_PORT_VALID(sc->sc_desc, i); i++) { 176102734Sphk if (i > 0 && rid == sc->sc_desc->ports[i].bar) 17790731Sjhay sc->barmuxed = 1; 17890731Sjhay rid = sc->sc_desc->ports[i].bar; 179102734Sphk bidx = puc_port_bar_index(sc, rid); 18090731Sjhay 18190731Sjhay if (sc->sc_bar_mappings[bidx].res != NULL) 18290731Sjhay continue; 18390731Sjhay res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 18490731Sjhay 0ul, ~0ul, 1, RF_ACTIVE); 18590731Sjhay if (res == NULL) { 18690731Sjhay printf("could not get resource\n"); 18790731Sjhay continue; 18890731Sjhay } 18990731Sjhay sc->sc_bar_mappings[bidx].res = res; 19090731Sjhay#ifdef PUC_DEBUG 191102734Sphk printf("port rid %d bst %x, start %x, end %x\n", rid, 19290731Sjhay (u_int)rman_get_bustag(res), (u_int)rman_get_start(res), 19390731Sjhay (u_int)rman_get_end(res)); 19490731Sjhay#endif 19590731Sjhay } 19690731Sjhay 197102734Sphk if (desc->init != NULL) { 198102734Sphk i = desc->init(sc); 199102734Sphk if (i != 0) 200102734Sphk return (i); 201102734Sphk } 20290731Sjhay 20390731Sjhay for (i = 0; PUC_PORT_VALID(sc->sc_desc, i); i++) { 20490731Sjhay rid = sc->sc_desc->ports[i].bar; 205102734Sphk bidx = puc_port_bar_index(sc, rid); 20690731Sjhay if (sc->sc_bar_mappings[bidx].res == NULL) 20790731Sjhay continue; 20890731Sjhay 20990731Sjhay switch (sc->sc_desc->ports[i].type) { 21090731Sjhay case PUC_PORT_TYPE_COM: 21190731Sjhay typestr = "sio"; 21290731Sjhay break; 21390731Sjhay default: 21490731Sjhay continue; 21590731Sjhay } 21690731Sjhay pdev = malloc(sizeof(struct puc_device), M_DEVBUF, 21790731Sjhay M_NOWAIT | M_ZERO); 21890731Sjhay if (!pdev) 21990731Sjhay continue; 22090731Sjhay resource_list_init(&pdev->resources); 22190731Sjhay 22290731Sjhay /* First fake up an IRQ resource. */ 22390731Sjhay resource_list_add(&pdev->resources, SYS_RES_IRQ, 0, 22490731Sjhay rman_get_start(sc->irqres), rman_get_end(sc->irqres), 22590731Sjhay rman_get_end(sc->irqres) - rman_get_start(sc->irqres) + 1); 22690731Sjhay rle = resource_list_find(&pdev->resources, SYS_RES_IRQ, 0); 22790731Sjhay rle->res = sc->irqres; 22890731Sjhay 22990731Sjhay /* Now fake an IOPORT resource */ 23090731Sjhay res = sc->sc_bar_mappings[bidx].res; 23190731Sjhay resource_list_add(&pdev->resources, SYS_RES_IOPORT, 0, 23290731Sjhay rman_get_start(res) + sc->sc_desc->ports[i].offset, 233102734Sphk rman_get_start(res) + sc->sc_desc->ports[i].offset + 8 - 1, 23490731Sjhay 8); 23590731Sjhay rle = resource_list_find(&pdev->resources, SYS_RES_IOPORT, 0); 23690731Sjhay 23790731Sjhay if (sc->barmuxed == 0) { 23890731Sjhay rle->res = sc->sc_bar_mappings[bidx].res; 23990731Sjhay } else { 24090731Sjhay rle->res = malloc(sizeof(struct resource), M_DEVBUF, 24190731Sjhay M_WAITOK | M_ZERO); 24290925Snyan if (rle->res == NULL) { 24390925Snyan free(pdev, M_DEVBUF); 24490731Sjhay return (ENOMEM); 24590925Snyan } 24690731Sjhay 24790731Sjhay rle->res->r_start = rman_get_start(res) + 24890731Sjhay sc->sc_desc->ports[i].offset; 24990731Sjhay rle->res->r_end = rle->res->r_start + 8 - 1; 25090731Sjhay rle->res->r_bustag = rman_get_bustag(res); 25190731Sjhay bus_space_subregion(rle->res->r_bustag, 25290731Sjhay rman_get_bushandle(res), 25390731Sjhay sc->sc_desc->ports[i].offset, 8, 25490731Sjhay &rle->res->r_bushandle); 25590731Sjhay } 25690731Sjhay 25790731Sjhay pdev->serialfreq = sc->sc_desc->ports[i].serialfreq; 25890731Sjhay 25990731Sjhay childunit = puc_find_free_unit(typestr); 26090731Sjhay sc->sc_ports[i].dev = device_add_child(dev, typestr, childunit); 26190925Snyan if (sc->sc_ports[i].dev == NULL) { 26290925Snyan if (sc->barmuxed) { 26390925Snyan bus_space_unmap(rman_get_bustag(rle->res), 26490925Snyan rman_get_bushandle(rle->res), 26590925Snyan 8); 26690925Snyan free(rle->res, M_DEVBUF); 26790925Snyan free(pdev, M_DEVBUF); 26890925Snyan } 26990731Sjhay continue; 27090925Snyan } 27190731Sjhay device_set_ivars(sc->sc_ports[i].dev, pdev); 27290731Sjhay device_set_desc(sc->sc_ports[i].dev, sc->sc_desc->name); 27390731Sjhay if (!bootverbose) 27490731Sjhay device_quiet(sc->sc_ports[i].dev); 27590731Sjhay#ifdef PUC_DEBUG 27690731Sjhay printf("puc: type %d, bar %x, offset %x\n", 27790731Sjhay sc->sc_desc->ports[i].type, 27890731Sjhay sc->sc_desc->ports[i].bar, 27990731Sjhay sc->sc_desc->ports[i].offset); 280102714Sphk puc_print_resource_list(&pdev->resources); 28190731Sjhay#endif 28290925Snyan if (device_probe_and_attach(sc->sc_ports[i].dev) != 0) { 28390925Snyan if (sc->barmuxed) { 28490925Snyan bus_space_unmap(rman_get_bustag(rle->res), 28590925Snyan rman_get_bushandle(rle->res), 28690925Snyan 8); 28790925Snyan free(rle->res, M_DEVBUF); 28890925Snyan free(pdev, M_DEVBUF); 28990925Snyan } 29090925Snyan } 29190731Sjhay } 29290731Sjhay 29390731Sjhay#ifdef PUC_DEBUG 29490731Sjhay bootverbose = 0; 29590731Sjhay#endif 29690731Sjhay return (0); 29790731Sjhay} 29890731Sjhay 29990731Sjhay/* 30090731Sjhay * This is just an brute force interrupt handler. It just calls all the 30190731Sjhay * registered handlers sequencially. 30290731Sjhay * 30390731Sjhay * Later on we should maybe have a different handler for boards that can 30490731Sjhay * tell us which device generated the interrupt. 30590731Sjhay */ 30690731Sjhaystatic void 30790731Sjhaypuc_intr(void *arg) 30890731Sjhay{ 30990731Sjhay int i; 31090731Sjhay struct puc_softc *sc; 31190731Sjhay 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} 339102894Sphk 340102894Sphkstatic int 341102894Sphkpuc_find_free_unit(char *name) 34290731Sjhay{ 34390731Sjhay devclass_t dc; 34490731Sjhay int start; 34590731Sjhay int unit; 34690731Sjhay 34790731Sjhay unit = 0; 34890731Sjhay start = 0; 34990731Sjhay while (resource_int_value(name, unit, "port", &start) == 0 && 35090731Sjhay start > 0) 35190731Sjhay unit++; 35290731Sjhay dc = devclass_find(name); 35390731Sjhay if (dc == NULL) 35490731Sjhay return (-1); 35590731Sjhay while (devclass_get_device(dc, unit)) 35690731Sjhay unit++; 35790731Sjhay#ifdef PUC_DEBUG 35890731Sjhay printf("puc: Using %s%d\n", name, unit); 35990731Sjhay#endif 36090731Sjhay return (unit); 36190731Sjhay} 36290731Sjhay 36390731Sjhay#ifdef PUC_DEBUG 36490731Sjhaystatic void 36590731Sjhaypuc_print_resource_list(struct resource_list *rl) 36690731Sjhay{ 367102734Sphk#if 0 36890731Sjhay struct resource_list_entry *rle; 36990731Sjhay 37090731Sjhay printf("print_resource_list: rl %p\n", rl); 37190731Sjhay SLIST_FOREACH(rle, rl, link) 372102734Sphk printf(" type %x, rid %x start %x end %x count %x\n", 373102734Sphk rle->type, rle->rid, rle->start, rle->end, rle->count); 37490731Sjhay printf("print_resource_list: end.\n"); 375102734Sphk#endif 37690731Sjhay} 37790731Sjhay#endif 37890731Sjhay 379102714Sphkstruct resource * 38090731Sjhaypuc_alloc_resource(device_t dev, device_t child, int type, int *rid, 38190731Sjhay u_long start, u_long end, u_long count, u_int flags) 38290731Sjhay{ 38390731Sjhay struct puc_device *pdev; 38490731Sjhay struct resource *retval; 38590731Sjhay struct resource_list *rl; 38690731Sjhay struct resource_list_entry *rle; 38790731Sjhay 38890731Sjhay pdev = device_get_ivars(child); 38990731Sjhay rl = &pdev->resources; 39090731Sjhay 39190731Sjhay#ifdef PUC_DEBUG 39290731Sjhay printf("puc_alloc_resource: pdev %p, looking for t %x, r %x\n", 39390731Sjhay pdev, type, *rid); 39490731Sjhay puc_print_resource_list(rl); 39590731Sjhay#endif 39690731Sjhay retval = NULL; 39790731Sjhay rle = resource_list_find(rl, type, *rid); 39890731Sjhay if (rle) { 39990731Sjhay start = rle->start; 40090731Sjhay end = rle->end; 40190731Sjhay count = rle->count; 40290731Sjhay#ifdef PUC_DEBUG 40390731Sjhay printf("found rle, %lx, %lx, %lx\n", start, end, count); 40490731Sjhay#endif 40590731Sjhay retval = rle->res; 40690731Sjhay } else 40790731Sjhay printf("oops rle is gone\n"); 40890731Sjhay 40990731Sjhay return (retval); 41090731Sjhay} 41190731Sjhay 412102714Sphkint 41390731Sjhaypuc_release_resource(device_t dev, device_t child, int type, int rid, 41490731Sjhay struct resource *res) 41590731Sjhay{ 41690731Sjhay return (0); 41790731Sjhay} 41890731Sjhay 419102714Sphkint 42090731Sjhaypuc_get_resource(device_t dev, device_t child, int type, int rid, 42190731Sjhay u_long *startp, u_long *countp) 42290731Sjhay{ 42390731Sjhay struct puc_device *pdev; 42490731Sjhay struct resource_list *rl; 42590731Sjhay struct resource_list_entry *rle; 42690731Sjhay 42790731Sjhay pdev = device_get_ivars(child); 42890731Sjhay rl = &pdev->resources; 42990731Sjhay 43090731Sjhay#ifdef PUC_DEBUG 43190731Sjhay printf("puc_get_resource: pdev %p, looking for t %x, r %x\n", pdev, 43290731Sjhay type, rid); 43390731Sjhay puc_print_resource_list(rl); 43490731Sjhay#endif 43590731Sjhay rle = resource_list_find(rl, type, rid); 43690731Sjhay if (rle) { 43790731Sjhay#ifdef PUC_DEBUG 43890731Sjhay printf("found rle %p,", rle); 43990731Sjhay#endif 44090731Sjhay if (startp != NULL) 44190731Sjhay *startp = rle->start; 44290731Sjhay if (countp != NULL) 44390731Sjhay *countp = rle->count; 44490731Sjhay#ifdef PUC_DEBUG 44590731Sjhay printf(" %lx, %lx\n", rle->start, rle->count); 44690731Sjhay#endif 44790731Sjhay return (0); 44890731Sjhay } else 44990731Sjhay printf("oops rle is gone\n"); 45090731Sjhay return (ENXIO); 45190731Sjhay} 45290731Sjhay 453102714Sphkint 45490731Sjhaypuc_setup_intr(device_t dev, device_t child, struct resource *r, int flags, 45590731Sjhay void (*ihand)(void *), void *arg, void **cookiep) 45690731Sjhay{ 45790731Sjhay int i; 45890731Sjhay struct puc_softc *sc; 45990731Sjhay 460102734Sphkprintf("puc_setup_intr()\n"); 46190731Sjhay sc = (struct puc_softc *)device_get_softc(dev); 46290731Sjhay for (i = 0; PUC_PORT_VALID(sc->sc_desc, i); i++) { 46390731Sjhay if (sc->sc_ports[i].dev == child) { 46490731Sjhay if (sc->sc_ports[i].ihand != 0) 46590731Sjhay return (ENXIO); 46690731Sjhay sc->sc_ports[i].ihand = ihand; 46790731Sjhay sc->sc_ports[i].ihandarg = arg; 46890731Sjhay *cookiep = arg; 46990731Sjhay return (0); 47090731Sjhay } 47190731Sjhay } 47290731Sjhay return (ENXIO); 47390731Sjhay} 47490731Sjhay 475102714Sphkint 47690731Sjhaypuc_teardown_intr(device_t dev, device_t child, struct resource *r, 47790731Sjhay void *cookie) 47890731Sjhay{ 47990731Sjhay int i; 48090731Sjhay struct puc_softc *sc; 48190731Sjhay 482102734Sphkprintf("puc_teardown_intr()\n"); 48390731Sjhay sc = (struct puc_softc *)device_get_softc(dev); 48490731Sjhay for (i = 0; PUC_PORT_VALID(sc->sc_desc, i); i++) { 48590731Sjhay if (sc->sc_ports[i].dev == child) { 48690731Sjhay sc->sc_ports[i].ihand = NULL; 48790731Sjhay sc->sc_ports[i].ihandarg = NULL; 48890731Sjhay return (0); 48990731Sjhay } 49090731Sjhay } 49190731Sjhay return (ENXIO); 49290731Sjhay} 49390731Sjhay 494102714Sphkint 49590731Sjhaypuc_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) 49690731Sjhay{ 49790731Sjhay struct puc_device *pdev; 49890731Sjhay 49990731Sjhay pdev = device_get_ivars(child); 50090731Sjhay if (pdev == NULL) 50190731Sjhay return (ENOENT); 50290731Sjhay 50390731Sjhay switch(index) { 50490731Sjhay case PUC_IVAR_FREQ: 50590731Sjhay *result = pdev->serialfreq; 50690731Sjhay break; 50790731Sjhay default: 50890731Sjhay return (ENOENT); 50990731Sjhay } 51090731Sjhay return (0); 51190731Sjhay} 512