puc.c revision 104068
121259Swollman/*	$NetBSD: puc.c,v 1.7 2000/07/29 17:43:38 jlam Exp $	*/
221259Swollman
321259Swollman/*-
421259Swollman * Copyright (c) 2002 JF Hay.  All rights reserved.
521259Swollman * Copyright (c) 2000 M. Warner Losh.  All rights reserved.
621259Swollman *
721259Swollman * Redistribution and use in source and binary forms, with or without
821259Swollman * modification, are permitted provided that the following conditions
921259Swollman * are met:
1021259Swollman * 1. Redistributions of source code must retain the above copyright
1121259Swollman *    notice unmodified, this list of conditions, and the following
1221259Swollman *    disclaimer.
1321259Swollman * 2. Redistributions in binary form must reproduce the above copyright
1421259Swollman *    notice, this list of conditions and the following disclaimer in the
1521259Swollman *    documentation and/or other materials provided with the distribution.
1621259Swollman *
1721259Swollman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1821259Swollman * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1921259Swollman * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2021259Swollman * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2121259Swollman * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2221259Swollman * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2321259Swollman * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2421259Swollman * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2521259Swollman * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2621259Swollman * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2721259Swollman */
2821259Swollman
2921259Swollman/*
3021259Swollman * Copyright (c) 1996, 1998, 1999
3121259Swollman *	Christopher G. Demetriou.  All rights reserved.
3221259Swollman *
3321259Swollman * Redistribution and use in source and binary forms, with or without
3450477Speter * modification, are permitted provided that the following conditions
3521259Swollman * are met:
3621259Swollman * 1. Redistributions of source code must retain the above copyright
3721259Swollman *    notice, this list of conditions and the following disclaimer.
3821259Swollman * 2. Redistributions in binary form must reproduce the above copyright
3921259Swollman *    notice, this list of conditions and the following disclaimer in the
4021259Swollman *    documentation and/or other materials provided with the distribution.
4121259Swollman * 3. All advertising materials mentioning features or use of this software
4221259Swollman *    must display the following acknowledgement:
4321259Swollman *      This product includes software developed by Christopher G. Demetriou
4421259Swollman *	for the NetBSD Project.
4521259Swollman * 4. The name of the author may not be used to endorse or promote products
4621259Swollman *    derived from this software without specific prior written permission
4721259Swollman *
4821259Swollman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
4921259Swollman * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
5021259Swollman * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
5121259Swollman * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
5221259Swollman * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
5321259Swollman * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
5421259Swollman * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
55108533Sschweikh * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
5621259Swollman * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
5721259Swollman * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5821259Swollman */
5921259Swollman
60108533Sschweikh#include <sys/cdefs.h>
6121259Swollman__FBSDID("$FreeBSD: head/sys/dev/puc/puc.c 104068 2002-09-27 22:01:32Z phk $");
6221259Swollman
6321259Swollman/*
6421259Swollman * PCI "universal" communication card device driver, glues com, lpt,
6521259Swollman * and similar ports to PCI via bridge chip often much larger than
6621259Swollman * the devices being glued.
6721259Swollman *
6821259Swollman * Author: Christopher G. Demetriou, May 14, 1998 (derived from NetBSD
6921259Swollman * sys/dev/pci/pciide.c, revision 1.6).
7083366Sjulian *
7121259Swollman * These devices could be (and some times are) described as
7285074Sru * communications/{serial,parallel}, etc. devices with known
7321259Swollman * programming interfaces, but those programming interfaces (in
7421259Swollman * particular the BAR assignments for devices, etc.) in fact are not
7521259Swollman * particularly well defined.
7621259Swollman *
77101849Srwatson * After I/we have seen more of these devices, it may be possible
7821259Swollman * to generalize some of these bits.  In particular, devices which
7921259Swollman * describe themselves as communications/serial/16[45]50, and
8069224Sjlemon * communications/parallel/??? might be attached via direct
8169152Sjlemon * 'com' and 'lpt' attachments to pci.
8269224Sjlemon */
8374914Sjhb
8474914Sjhb#include "opt_puc.h"
8583130Sjlemon
8669152Sjlemon#include <sys/param.h>
8760938Sjake#include <sys/systm.h>
8860938Sjake#include <sys/kernel.h>
8960938Sjake#include <sys/bus.h>
9072084Sphk#include <sys/conf.h>
9121259Swollman#include <sys/malloc.h>
9221259Swollman
9321259Swollman#include <machine/bus.h>
9421259Swollman#include <machine/resource.h>
9521259Swollman#include <sys/rman.h>
9621259Swollman
9721259Swollman#include <dev/pci/pcireg.h>
9821259Swollman#include <dev/pci/pcivar.h>
9921259Swollman
10021259Swollman#define PUC_ENTRAILS	1
10169152Sjlemon#include <dev/puc/pucvar.h>
10221259Swollman
10321259Swollmanstruct puc_device {
10421259Swollman	struct resource_list resources;
10521259Swollman	u_int serialfreq;
10621259Swollman};
10721259Swollman
10821259Swollmanstatic void puc_intr(void *arg);
10984380Smjacob
11084380Smjacobstatic int puc_find_free_unit(char *);
11184380Smjacob#ifdef PUC_DEBUG
11284380Smjacobstatic void puc_print_resource_list(struct resource_list *);
11386797Sluigi#endif
11486797Sluigi
11586797Sluigidevclass_t puc_devclass;
11686797Sluigi
11786797Sluigistatic int
11886797Sluigipuc_port_bar_index(struct puc_softc *sc, int bar)
11986797Sluigi{
12086797Sluigi	int i;
12186797Sluigi
12286797Sluigi	for (i = 0; i < PUC_MAX_BAR; i += 1) {
12386797Sluigi		if (!sc->sc_bar_mappings[i].used)
12486797Sluigi			break;
12586797Sluigi		if (sc->sc_bar_mappings[i].bar == bar)
12686797Sluigi			return (i);
12786797Sluigi	}
12884380Smjacob	sc->sc_bar_mappings[i].bar = bar;
12921259Swollman	sc->sc_bar_mappings[i].used = 1;
13021259Swollman	return (i);
13121259Swollman}
13260938Sjake
13321259Swollmanint
13483130Sjlemonpuc_attach(device_t dev, const struct puc_device_description *desc)
13583130Sjlemon{
13621259Swollman	char *typestr;
13721259Swollman	int bidx, childunit, i, irq_setup, rid;
13821259Swollman	struct puc_softc *sc;
13921259Swollman	struct puc_device *pdev;
140106931Ssam	struct resource *res;
141102052Ssobomax	struct resource_list_entry *rle;
14283624Sjlemon
14383624Sjlemon	sc = (struct puc_softc *)device_get_softc(dev);
14421259Swollman	bzero(sc, sizeof(*sc));
14521259Swollman	sc->sc_desc = desc;
14621259Swollman	if (sc->sc_desc == NULL)
14721259Swollman		return (ENXIO);
14821404Swollman
14921404Swollman#ifdef PUC_DEBUG
15021259Swollman	bootverbose = 1;
15121259Swollman
15292725Salfred	printf("puc: name: %s\n", sc->sc_desc->name);
15392725Salfred#endif
154106931Ssam	rid = 0;
155106931Ssam	res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
15621259Swollman	    RF_ACTIVE | RF_SHAREABLE);
15792725Salfred	if (!res)
15821259Swollman		return (ENXIO);
15992725Salfred
16021259Swollman	sc->irqres = res;
16192725Salfred	sc->irqrid = rid;
16221259Swollman#ifdef PUC_FASTINTR
16392725Salfred	irq_setup = BUS_SETUP_INTR(device_get_parent(dev), dev, res,
16421259Swollman	    INTR_TYPE_TTY | INTR_FAST, puc_intr, sc, &sc->intr_cookie);
16592725Salfred	if (irq_setup == 0)
16621259Swollman		sc->fastintr = INTR_FAST;
16792725Salfred	else
16821259Swollman		irq_setup = BUS_SETUP_INTR(device_get_parent(dev), dev, res,
16992725Salfred		    INTR_TYPE_TTY, puc_intr, sc, &sc->intr_cookie);
17021259Swollman#else
17192725Salfred	irq_setup = BUS_SETUP_INTR(device_get_parent(dev), dev, res,
17221259Swollman	    INTR_TYPE_TTY, puc_intr, sc, &sc->intr_cookie);
17392725Salfred#endif
17421404Swollman	if (irq_setup != 0)
17592725Salfred		return (ENXIO);
17621259Swollman
17721259Swollman	rid = 0;
17852904Sshin	for (i = 0; PUC_PORT_VALID(sc->sc_desc, i); i++) {
17984931Sfjoe		if (i > 0 && rid == sc->sc_desc->ports[i].bar)
180100992Srwatson			sc->barmuxed = 1;
18121259Swollman		rid = sc->sc_desc->ports[i].bar;
18269152Sjlemon		bidx = puc_port_bar_index(sc, rid);
18392725Salfred
18421259Swollman		if (sc->sc_bar_mappings[bidx].res != NULL)
18521259Swollman			continue;
18621259Swollman		res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
18721259Swollman		    0ul, ~0ul, 1, RF_ACTIVE);
18821259Swollman		if (res == NULL) {
18921259Swollman			printf("could not get resource\n");
19021259Swollman			continue;
19121259Swollman		}
19258698Sjlemon		sc->sc_bar_mappings[bidx].res = res;
19321259Swollman#ifdef PUC_DEBUG
19421259Swollman		printf("port rid %d bst %x, start %x, end %x\n", rid,
19521259Swollman		    (u_int)rman_get_bustag(res), (u_int)rman_get_start(res),
19621259Swollman		    (u_int)rman_get_end(res));
19721259Swollman#endif
19821259Swollman	}
19921259Swollman
20021259Swollman	if (desc->init != NULL) {
20121259Swollman		i = desc->init(sc);
20221259Swollman		if (i != 0)
20321259Swollman			return (i);
20421259Swollman	}
20521259Swollman
20621259Swollman	for (i = 0; PUC_PORT_VALID(sc->sc_desc, i); i++) {
20721259Swollman		rid = sc->sc_desc->ports[i].bar;
20821259Swollman		bidx = puc_port_bar_index(sc, rid);
20953541Sshin		if (sc->sc_bar_mappings[bidx].res == NULL)
21053541Sshin			continue;
21153541Sshin
21253541Sshin		switch (sc->sc_desc->ports[i].type) {
21321259Swollman		case PUC_PORT_TYPE_COM:
21421259Swollman			typestr = "sio";
21521259Swollman			break;
21621259Swollman		default:
21721259Swollman			continue;
21821259Swollman		}
21921259Swollman		pdev = malloc(sizeof(struct puc_device), M_DEVBUF,
22021259Swollman		    M_NOWAIT | M_ZERO);
22121259Swollman		if (!pdev)
22221259Swollman			continue;
22321259Swollman		resource_list_init(&pdev->resources);
22421259Swollman
22572200Sbmilekic		/* First fake up an IRQ resource. */
22672200Sbmilekic		resource_list_add(&pdev->resources, SYS_RES_IRQ, 0,
22769152Sjlemon		    rman_get_start(sc->irqres), rman_get_end(sc->irqres),
22869152Sjlemon		    rman_get_end(sc->irqres) - rman_get_start(sc->irqres) + 1);
22969152Sjlemon		rle = resource_list_find(&pdev->resources, SYS_RES_IRQ, 0);
23021259Swollman		rle->res = sc->irqres;
23169152Sjlemon
23269152Sjlemon		/* Now fake an IOPORT resource */
23369152Sjlemon		res = sc->sc_bar_mappings[bidx].res;
23469152Sjlemon		resource_list_add(&pdev->resources, SYS_RES_IOPORT, 0,
23569152Sjlemon		    rman_get_start(res) + sc->sc_desc->ports[i].offset,
23669152Sjlemon		    rman_get_start(res) + sc->sc_desc->ports[i].offset + 8 - 1,
23769152Sjlemon		    8);
23869152Sjlemon		rle = resource_list_find(&pdev->resources, SYS_RES_IOPORT, 0);
23969152Sjlemon
24069152Sjlemon		if (sc->barmuxed == 0) {
24169152Sjlemon			rle->res = sc->sc_bar_mappings[bidx].res;
24269152Sjlemon		} else {
24369152Sjlemon			rle->res = malloc(sizeof(struct resource), M_DEVBUF,
24469152Sjlemon			    M_WAITOK | M_ZERO);
24569152Sjlemon			if (rle->res == NULL) {
24669152Sjlemon				free(pdev, M_DEVBUF);
24769152Sjlemon				return (ENOMEM);
24869152Sjlemon			}
24969152Sjlemon
25069152Sjlemon			rle->res->r_start = rman_get_start(res) +
25169152Sjlemon			    sc->sc_desc->ports[i].offset;
25269152Sjlemon			rle->res->r_end = rle->res->r_start + 8 - 1;
25369152Sjlemon			rle->res->r_bustag = rman_get_bustag(res);
25469152Sjlemon			bus_space_subregion(rle->res->r_bustag,
25569152Sjlemon			    rman_get_bushandle(res),
25669152Sjlemon			    sc->sc_desc->ports[i].offset, 8,
25769152Sjlemon			    &rle->res->r_bushandle);
25869152Sjlemon		}
25969152Sjlemon
26069152Sjlemon		pdev->serialfreq = sc->sc_desc->ports[i].serialfreq;
26169152Sjlemon
26269152Sjlemon		childunit = puc_find_free_unit(typestr);
26369152Sjlemon		sc->sc_ports[i].dev = device_add_child(dev, typestr, childunit);
26469152Sjlemon		if (sc->sc_ports[i].dev == NULL) {
26569152Sjlemon			if (sc->barmuxed) {
26669152Sjlemon				bus_space_unmap(rman_get_bustag(rle->res),
26769152Sjlemon						rman_get_bushandle(rle->res),
26869152Sjlemon						8);
26969152Sjlemon				free(rle->res, M_DEVBUF);
27069152Sjlemon				free(pdev, M_DEVBUF);
27169152Sjlemon			}
27269152Sjlemon			continue;
27369152Sjlemon		}
27469152Sjlemon		device_set_ivars(sc->sc_ports[i].dev, pdev);
27569152Sjlemon		device_set_desc(sc->sc_ports[i].dev, sc->sc_desc->name);
27669152Sjlemon		if (!bootverbose)
27769152Sjlemon			device_quiet(sc->sc_ports[i].dev);
27869152Sjlemon#ifdef PUC_DEBUG
27969152Sjlemon		printf("puc: type %d, bar %x, offset %x\n",
28069152Sjlemon		    sc->sc_desc->ports[i].type,
28169152Sjlemon		    sc->sc_desc->ports[i].bar,
28269152Sjlemon		    sc->sc_desc->ports[i].offset);
28369152Sjlemon		puc_print_resource_list(&pdev->resources);
28469152Sjlemon#endif
28569152Sjlemon		device_set_flags(sc->sc_ports[i].dev,
28669152Sjlemon		    sc->sc_desc->ports[i].flags);
28769152Sjlemon		if (device_probe_and_attach(sc->sc_ports[i].dev) != 0) {
28869152Sjlemon			if (sc->barmuxed) {
28955205Speter				bus_space_unmap(rman_get_bustag(rle->res),
29069152Sjlemon						rman_get_bushandle(rle->res),
29169152Sjlemon						8);
29221259Swollman				free(rle->res, M_DEVBUF);
29335210Sbde				free(pdev, M_DEVBUF);
29469152Sjlemon			}
29521259Swollman		}
29669152Sjlemon	}
29721259Swollman
29869152Sjlemon#ifdef PUC_DEBUG
29969152Sjlemon	bootverbose = 0;
30069152Sjlemon#endif
30169152Sjlemon	return (0);
30269152Sjlemon}
30369152Sjlemon
30469152Sjlemon/*
30569152Sjlemon * This is just an brute force interrupt handler. It just calls all the
30669152Sjlemon * registered handlers sequencially.
30769152Sjlemon *
30869152Sjlemon * Later on we should maybe have a different handler for boards that can
30969152Sjlemon * tell us which device generated the interrupt.
31069152Sjlemon */
31169152Sjlemonstatic void
31269152Sjlemonpuc_intr(void *arg)
31386364Sjhb{
31496173Simp	int i;
31569152Sjlemon	struct puc_softc *sc;
31621259Swollman
31721259Swollman	sc = (struct puc_softc *)arg;
31849459Sbrian	for (i = 0; i < PUC_MAX_PORTS; i++)
31949459Sbrian		if (sc->sc_ports[i].ihand != NULL)
32049459Sbrian			(sc->sc_ports[i].ihand)(sc->sc_ports[i].ihandarg);
32149459Sbrian}
32249459Sbrian
32349459Sbrianconst struct puc_device_description *
32449459Sbrianpuc_find_description(uint32_t vend, uint32_t prod, uint32_t svend,
32555205Speter    uint32_t sprod)
32621259Swollman{
32721259Swollman	int i;
32821259Swollman
32921259Swollman#define checkreg(val, index) \
33021259Swollman    (((val) & puc_devices[i].rmask[(index)]) == puc_devices[i].rval[(index)])
33121259Swollman
33221259Swollman	for (i = 0; puc_devices[i].name != NULL; i++) {
33321259Swollman		if (checkreg(vend, PUC_REG_VEND) &&
33421259Swollman		    checkreg(prod, PUC_REG_PROD) &&
33521259Swollman		    checkreg(svend, PUC_REG_SVEND) &&
33621259Swollman		    checkreg(sprod, PUC_REG_SPROD))
33721259Swollman			return (&puc_devices[i]);
33867334Sjoe	}
33921259Swollman
34060938Sjake#undef checkreg
34121259Swollman
34292725Salfred	return (NULL);
34321259Swollman}
34447254Spb
34521259Swollmanstatic int
34621259Swollmanpuc_find_free_unit(char *name)
34721259Swollman{
34821259Swollman	devclass_t dc;
34928845Sjulian	int start;
35092725Salfred	int unit;
351108033Shsu
35221259Swollman	unit = 0;
35321259Swollman	start = 0;
35421259Swollman	while (resource_int_value(name, unit, "port", &start) == 0 &&
35553541Sshin	    start > 0)
35653541Sshin		unit++;
35753541Sshin	dc = devclass_find(name);
358108033Shsu	if (dc == NULL)
359108033Shsu		return (-1);
360108033Shsu	while (devclass_get_device(dc, unit))
361108033Shsu		unit++;
362108033Shsu#ifdef PUC_DEBUG
363108033Shsu	printf("puc: Using %s%d\n", name, unit);
36421404Swollman#endif
36552904Sshin	return (unit);
36652904Sshin}
367108470Sschweikh
36853541Sshin#ifdef PUC_DEBUG
36952904Sshinstatic void
37052904Sshinpuc_print_resource_list(struct resource_list *rl)
37152904Sshin{
37252904Sshin#if 0
37360938Sjake	struct resource_list_entry *rle;
37452904Sshin
37552904Sshin	printf("print_resource_list: rl %p\n", rl);
37652904Sshin	SLIST_FOREACH(rle, rl, link)
37752904Sshin		printf("  type %x, rid %x start %x end %x count %x\n",
37852904Sshin		    rle->type, rle->rid, rle->start, rle->end, rle->count);
37921404Swollman	printf("print_resource_list: end.\n");
38021404Swollman#endif
38121404Swollman}
38221404Swollman#endif
38321404Swollman
38421404Swollmanstruct resource *
38572084Sphkpuc_alloc_resource(device_t dev, device_t child, int type, int *rid,
38621434Swollman    u_long start, u_long end, u_long count, u_int flags)
38721434Swollman{
38821434Swollman	struct puc_device *pdev;
38921434Swollman	struct resource *retval;
39021434Swollman	struct resource_list *rl;
39121404Swollman	struct resource_list_entry *rle;
39221404Swollman
39355205Speter	pdev = device_get_ivars(child);
394108036Shsu	rl = &pdev->resources;
395108036Shsu
396108036Shsu#ifdef PUC_DEBUG
397108036Shsu	printf("puc_alloc_resource: pdev %p, looking for t %x, r %x\n",
398108036Shsu	    pdev, type, *rid);
399108036Shsu	puc_print_resource_list(rl);
400108036Shsu#endif
401108036Shsu	retval = NULL;
402108036Shsu	rle = resource_list_find(rl, type, *rid);
403108036Shsu	if (rle) {
40446568Speter		start = rle->start;
40521259Swollman		end = rle->end;
406108036Shsu		count = rle->count;
407108036Shsu#ifdef PUC_DEBUG
408108036Shsu		printf("found rle, %lx, %lx, %lx\n", start, end, count);
409108036Shsu#endif
410108036Shsu		retval = rle->res;
411108033Shsu	} else
412108033Shsu		printf("oops rle is gone\n");
413108172Shsu
414108298Shsu	return (retval);
415108298Shsu}
416108172Shsu
417108172Shsuint
418108172Shsupuc_release_resource(device_t dev, device_t child, int type, int rid,
419108172Shsu    struct resource *res)
420108172Shsu{
42183130Sjlemon	return (0);
42287914Sjlemon}
42383130Sjlemon
42483130Sjlemonint
42583130Sjlemonpuc_get_resource(device_t dev, device_t child, int type, int rid,
42683130Sjlemon    u_long *startp, u_long *countp)
42783130Sjlemon{
42883130Sjlemon	struct puc_device *pdev;
42983130Sjlemon	struct resource_list *rl;
43083130Sjlemon	struct resource_list_entry *rle;
43121259Swollman
43283130Sjlemon	pdev = device_get_ivars(child);
43321259Swollman	rl = &pdev->resources;
43471791Speter
43521259Swollman#ifdef PUC_DEBUG
43621259Swollman	printf("puc_get_resource: pdev %p, looking for t %x, r %x\n", pdev,
43792725Salfred	    type, rid);
43892725Salfred	puc_print_resource_list(rl);
43992725Salfred#endif
44092725Salfred	rle = resource_list_find(rl, type, rid);
44192725Salfred	if (rle) {
44292725Salfred#ifdef PUC_DEBUG
443103900Sbrooks		printf("found rle %p,", rle);
44492725Salfred#endif
44592725Salfred		if (startp != NULL)
44692725Salfred			*startp = rle->start;
44792725Salfred		if (countp != NULL)
44892725Salfred			*countp = rle->count;
44992725Salfred#ifdef PUC_DEBUG
45092725Salfred		printf(" %lx, %lx\n", rle->start, rle->count);
45192725Salfred#endif
45292725Salfred		return (0);
45321259Swollman	} else
45492725Salfred		printf("oops rle is gone\n");
45592725Salfred	return (ENXIO);
45692725Salfred}
45792725Salfred
45892725Salfredint
45992725Salfredpuc_setup_intr(device_t dev, device_t child, struct resource *r, int flags,
46021259Swollman	       void (*ihand)(void *), void *arg, void **cookiep)
46192725Salfred{
46292725Salfred	int i;
46392725Salfred	struct puc_softc *sc;
46492725Salfred
46592725Salfred	sc = (struct puc_softc *)device_get_softc(dev);
46621259Swollman	if ((flags & INTR_FAST) != sc->fastintr)
46792725Salfred		return (ENXIO);
46892725Salfred	for (i = 0; PUC_PORT_VALID(sc->sc_desc, i); i++) {
46921434Swollman		if (sc->sc_ports[i].dev == child) {
47092725Salfred			if (sc->sc_ports[i].ihand != 0)
47192725Salfred				return (ENXIO);
47279103Sbrooks			sc->sc_ports[i].ihand = ihand;
47392725Salfred			sc->sc_ports[i].ihandarg = arg;
47492725Salfred			*cookiep = arg;
47579103Sbrooks			return (0);
47684931Sfjoe		}
47784931Sfjoe	}
47884931Sfjoe	return (ENXIO);
47987902Sluigi}
48087902Sluigi
48187902Sluigiint
48292725Salfredpuc_teardown_intr(device_t dev, device_t child, struct resource *r,
48392725Salfred		  void *cookie)
48492725Salfred{
48587902Sluigi	int i;
48687902Sluigi	struct puc_softc *sc;
48755205Speter
48821259Swollman	sc = (struct puc_softc *)device_get_softc(dev);
48921259Swollman	for (i = 0; PUC_PORT_VALID(sc->sc_desc, i); i++) {
490		if (sc->sc_ports[i].dev == child) {
491			sc->sc_ports[i].ihand = NULL;
492			sc->sc_ports[i].ihandarg = NULL;
493			return (0);
494		}
495	}
496	return (ENXIO);
497}
498
499int
500puc_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
501{
502	struct puc_device *pdev;
503
504	pdev = device_get_ivars(child);
505	if (pdev == NULL)
506		return (ENOENT);
507
508	switch(index) {
509	case PUC_IVAR_FREQ:
510		*result = pdev->serialfreq;
511		break;
512	default:
513		return (ENOENT);
514	}
515	return (0);
516}
517