puc.c revision 112270
190731Sjhay/*	$NetBSD: puc.c,v 1.7 2000/07/29 17:43:38 jlam Exp $	*/
2158124Smarcel
3158124Smarcel/*-
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:
36158124Smarcel * 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
44102714Sphk *	for the NetBSD Project.
45158124Smarcel * 4. The name of the author may not be used to endorse or promote products
46158124Smarcel *    derived from this software without specific prior written permission
47160030Sobrien *
4890731Sjhay * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
49158124Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
5090731Sjhay * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
51158124Smarcel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
52158124Smarcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
53158124Smarcel * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
54158124Smarcel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
55158124Smarcel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
56158124Smarcel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
57158124Smarcel * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
58158124Smarcel */
5990731Sjhay
60158124Smarcel#include <sys/cdefs.h>
6190731Sjhay__FBSDID("$FreeBSD: head/sys/dev/puc/puc.c 112270 2003-03-15 16:25:40Z sobomax $");
62158124Smarcel
63158124Smarcel/*
64158124Smarcel * PCI "universal" communication card device driver, glues com, lpt,
65158124Smarcel * and similar ports to PCI via bridge chip often much larger than
66158124Smarcel * the devices being glued.
67158124Smarcel *
68158124Smarcel * Author: Christopher G. Demetriou, May 14, 1998 (derived from NetBSD
69102893Sphk * sys/dev/pci/pciide.c, revision 1.6).
70158124Smarcel *
71102893Sphk * These devices could be (and some times are) described as
72158124Smarcel * communications/{serial,parallel}, etc. devices with known
73158124Smarcel * programming interfaces, but those programming interfaces (in
74158124Smarcel * particular the BAR assignments for devices, etc.) in fact are not
75158124Smarcel * particularly well defined.
76102734Sphk *
77158124Smarcel * After I/we have seen more of these devices, it may be possible
78158124Smarcel * to generalize some of these bits.  In particular, devices which
79158124Smarcel * describe themselves as communications/serial/16[45]50, and
80158124Smarcel * communications/parallel/??? might be attached via direct
81102734Sphk * 'com' and 'lpt' attachments to pci.
82158124Smarcel */
83158124Smarcel
84158124Smarcel#include "opt_puc.h"
85158124Smarcel
86158124Smarcel#include <sys/param.h>
87158124Smarcel#include <sys/systm.h>
88158124Smarcel#include <sys/kernel.h>
89158124Smarcel#include <sys/bus.h>
90158124Smarcel#include <sys/conf.h>
91158124Smarcel#include <sys/malloc.h>
92158124Smarcel
93158124Smarcel#include <machine/bus.h>
94158124Smarcel#include <machine/resource.h>
95158124Smarcel#include <sys/rman.h>
96158124Smarcel
97158124Smarcel#include <dev/pci/pcireg.h>
98158124Smarcel#include <dev/pci/pcivar.h>
99158124Smarcel
100158124Smarcel#define PUC_ENTRAILS	1
101158124Smarcel#include <dev/puc/pucvar.h>
102158124Smarcel
103158124Smarcelstruct puc_device {
104158124Smarcel	struct resource_list resources;
105158124Smarcel	u_int serialfreq;
106158124Smarcel};
107158124Smarcel
108158124Smarcelstatic void puc_intr(void *arg);
109158124Smarcel
110102734Sphkstatic int puc_find_free_unit(char *);
111158124Smarcel#ifdef PUC_DEBUG
112158124Smarcelstatic void puc_print_resource_list(struct resource_list *);
113158124Smarcel#endif
114158124Smarcel
115158124Smarceldevclass_t puc_devclass;
116158124Smarcel
117158124Smarcelstatic int
118158124Smarcelpuc_port_bar_index(struct puc_softc *sc, int bar)
119158124Smarcel{
120158124Smarcel	int i;
121158124Smarcel
122158124Smarcel	for (i = 0; i < PUC_MAX_BAR; i += 1) {
123142502Ssam		if (!sc->sc_bar_mappings[i].used)
124158124Smarcel			break;
125158124Smarcel		if (sc->sc_bar_mappings[i].bar == bar)
126102734Sphk			return (i);
127102734Sphk	}
128158124Smarcel	sc->sc_bar_mappings[i].bar = bar;
129158124Smarcel	sc->sc_bar_mappings[i].used = 1;
130112270Ssobomax	return (i);
131158124Smarcel}
132158124Smarcel
133158124Smarcelstatic int
134158124Smarcelpuc_probe_ilr(struct puc_softc *sc, struct resource *res)
135158124Smarcel{
136112270Ssobomax	u_char t1, t2;
137158124Smarcel	int i;
138158124Smarcel
139158124Smarcel	switch (sc->sc_desc->ilr_type) {
140158124Smarcel	case PUC_ILR_TYPE_DIGI:
141158124Smarcel		sc->ilr_st = rman_get_bustag(res);
142158124Smarcel		sc->ilr_sh = rman_get_bushandle(res);
143158124Smarcel		for (i = 0; i < 2; i++) {
144112270Ssobomax			t1 = bus_space_read_1(sc->ilr_st, sc->ilr_sh,
145158124Smarcel			    sc->sc_desc->ilr_offset[i]);
146158124Smarcel			t1 = ~t1;
147158124Smarcel			bus_space_write_1(sc->ilr_st, sc->ilr_sh,
148158124Smarcel			    sc->sc_desc->ilr_offset[i], t1);
149158124Smarcel			t2 = bus_space_read_1(sc->ilr_st, sc->ilr_sh,
150158124Smarcel			    sc->sc_desc->ilr_offset[i]);
151158124Smarcel			if (t2 == t1)
152158124Smarcel				return (0);
153158124Smarcel		}
154158124Smarcel		return (1);
155158124Smarcel
156112270Ssobomax	default:
157158124Smarcel		break;
158158124Smarcel	}
159158124Smarcel	return (0);
160158124Smarcel}
161158124Smarcel
162158124Smarcelint
163158124Smarcelpuc_attach(device_t dev, const struct puc_device_description *desc)
164158124Smarcel{
165158124Smarcel	char *typestr;
166112270Ssobomax	int bidx, childunit, i, irq_setup, rid, type;
167158124Smarcel	struct puc_softc *sc;
168158124Smarcel	struct puc_device *pdev;
169158124Smarcel	struct resource *res;
170158124Smarcel	struct resource_list_entry *rle;
171158124Smarcel
172158124Smarcel	sc = (struct puc_softc *)device_get_softc(dev);
173158124Smarcel	bzero(sc, sizeof(*sc));
174158124Smarcel	sc->sc_desc = desc;
175158124Smarcel	if (sc->sc_desc == NULL)
176158124Smarcel		return (ENXIO);
177158124Smarcel
178158124Smarcel#ifdef PUC_DEBUG
179158124Smarcel	bootverbose = 1;
180158124Smarcel
181158124Smarcel	printf("puc: name: %s\n", sc->sc_desc->name);
182158124Smarcel#endif
183158124Smarcel	rid = 0;
184158124Smarcel	res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
185158124Smarcel	    RF_ACTIVE | RF_SHAREABLE);
186158124Smarcel	if (!res)
187112270Ssobomax		return (ENXIO);
188112270Ssobomax
189102714Sphk	sc->irqres = res;
190158124Smarcel	sc->irqrid = rid;
19190731Sjhay#ifdef PUC_FASTINTR
192158124Smarcel	irq_setup = BUS_SETUP_INTR(device_get_parent(dev), dev, res,
193158124Smarcel	    INTR_TYPE_TTY | INTR_FAST, puc_intr, sc, &sc->intr_cookie);
194158124Smarcel	if (irq_setup == 0)
19590731Sjhay		sc->fastintr = INTR_FAST;
196158124Smarcel	else
197158124Smarcel		irq_setup = BUS_SETUP_INTR(device_get_parent(dev), dev, res,
198158124Smarcel		    INTR_TYPE_TTY, puc_intr, sc, &sc->intr_cookie);
199158124Smarcel#else
200158124Smarcel	irq_setup = BUS_SETUP_INTR(device_get_parent(dev), dev, res,
201158124Smarcel	    INTR_TYPE_TTY, puc_intr, sc, &sc->intr_cookie);
202158124Smarcel#endif
20390731Sjhay	if (irq_setup != 0)
204158124Smarcel		return (ENXIO);
205119814Smarcel
206158124Smarcel	rid = 0;
207158124Smarcel	for (i = 0; PUC_PORT_VALID(sc->sc_desc, i); i++) {
20890731Sjhay		if (i > 0 && rid == sc->sc_desc->ports[i].bar)
209158124Smarcel			sc->barmuxed = 1;
210158124Smarcel		rid = sc->sc_desc->ports[i].bar;
211158124Smarcel		bidx = puc_port_bar_index(sc, rid);
212158124Smarcel
213158124Smarcel		if (sc->sc_bar_mappings[bidx].res != NULL)
214158124Smarcel			continue;
215158124Smarcel
216158124Smarcel		type = (sc->sc_desc->ports[i].flags & PUC_FLAGS_MEMORY)
217158124Smarcel		    ? SYS_RES_MEMORY : SYS_RES_IOPORT;
218158124Smarcel
219158124Smarcel		res = bus_alloc_resource(dev, type, &rid, 0ul, ~0ul, 1,
220158124Smarcel		    RF_ACTIVE);
221158124Smarcel		if (res == NULL) {
222158124Smarcel			printf("could not get resource\n");
223158124Smarcel			continue;
224158124Smarcel		}
225158124Smarcel		sc->sc_bar_mappings[bidx].type = type;
22690731Sjhay		sc->sc_bar_mappings[bidx].res = res;
227158124Smarcel
228158124Smarcel		if (sc->sc_desc->ilr_type != PUC_ILR_TYPE_NONE) {
229158124Smarcel			sc->ilr_enabled = puc_probe_ilr(sc, res);
230158124Smarcel			if (sc->ilr_enabled)
231158124Smarcel				device_printf(dev, "ILR enabled\n");
232158124Smarcel			else
233158124Smarcel				device_printf(dev, "ILR disabled\n");
234158124Smarcel		}
235158124Smarcel#ifdef PUC_DEBUG
23690731Sjhay		printf("%s rid %d bst %x, start %x, end %x\n",
237158124Smarcel		    (type == SYS_RES_MEMORY) ? "memory" : "port", rid,
238158124Smarcel		    (u_int)rman_get_bustag(res), (u_int)rman_get_start(res),
239158124Smarcel		    (u_int)rman_get_end(res));
240158124Smarcel#endif
241158124Smarcel	}
24290731Sjhay
243158124Smarcel	if (desc->init != NULL) {
244158124Smarcel		i = desc->init(sc);
245158124Smarcel		if (i != 0)
24690731Sjhay			return (i);
247158124Smarcel	}
248158124Smarcel
249158124Smarcel	for (i = 0; PUC_PORT_VALID(sc->sc_desc, i); i++) {
250109458Smarcel		rid = sc->sc_desc->ports[i].bar;
251158124Smarcel		bidx = puc_port_bar_index(sc, rid);
252158124Smarcel		if (sc->sc_bar_mappings[bidx].res == NULL)
253158124Smarcel			continue;
254158124Smarcel
255158124Smarcel		switch (sc->sc_desc->ports[i].type) {
256158124Smarcel		case PUC_PORT_TYPE_COM:
257158124Smarcel			typestr = "sio";
258158124Smarcel			break;
259158124Smarcel		default:
260158124Smarcel			continue;
261158124Smarcel		}
262158124Smarcel		pdev = malloc(sizeof(struct puc_device), M_DEVBUF,
263158124Smarcel		    M_NOWAIT | M_ZERO);
264158124Smarcel		if (!pdev)
265119814Smarcel			continue;
266158124Smarcel		resource_list_init(&pdev->resources);
267158124Smarcel
268158124Smarcel		/* First fake up an IRQ resource. */
269158124Smarcel		resource_list_add(&pdev->resources, SYS_RES_IRQ, 0,
270158124Smarcel		    rman_get_start(sc->irqres), rman_get_end(sc->irqres),
271158124Smarcel		    rman_get_end(sc->irqres) - rman_get_start(sc->irqres) + 1);
272158124Smarcel		rle = resource_list_find(&pdev->resources, SYS_RES_IRQ, 0);
273158124Smarcel		rle->res = sc->irqres;
274158124Smarcel
275158124Smarcel		/* Now fake an IOPORT or MEMORY resource */
276158124Smarcel		res = sc->sc_bar_mappings[bidx].res;
277158124Smarcel		type = sc->sc_bar_mappings[bidx].type;
278158124Smarcel		resource_list_add(&pdev->resources, type, 0,
279158124Smarcel		    rman_get_start(res) + sc->sc_desc->ports[i].offset,
280158124Smarcel		    rman_get_start(res) + sc->sc_desc->ports[i].offset + 8 - 1,
281158124Smarcel		    8);
282158124Smarcel		rle = resource_list_find(&pdev->resources, type, 0);
283158124Smarcel
284158124Smarcel		if (sc->barmuxed == 0) {
285158124Smarcel			rle->res = sc->sc_bar_mappings[bidx].res;
28690731Sjhay		} else {
287158124Smarcel			rle->res = malloc(sizeof(struct resource), M_DEVBUF,
288158124Smarcel			    M_WAITOK | M_ZERO);
289158124Smarcel			if (rle->res == NULL) {
290158124Smarcel				free(pdev, M_DEVBUF);
291158124Smarcel				return (ENOMEM);
292112270Ssobomax			}
293158124Smarcel
294158124Smarcel			rle->res->r_start = rman_get_start(res) +
295158124Smarcel			    sc->sc_desc->ports[i].offset;
296158124Smarcel			rle->res->r_end = rle->res->r_start + 8 - 1;
29790731Sjhay			rle->res->r_bustag = rman_get_bustag(res);
298158124Smarcel			bus_space_subregion(rle->res->r_bustag,
299158124Smarcel			    rman_get_bushandle(res),
300158124Smarcel			    sc->sc_desc->ports[i].offset, 8,
301102734Sphk			    &rle->res->r_bushandle);
30290731Sjhay		}
303158124Smarcel
304158124Smarcel		pdev->serialfreq = sc->sc_desc->ports[i].serialfreq;
305158124Smarcel
306158124Smarcel		childunit = puc_find_free_unit(typestr);
307158124Smarcel		sc->sc_ports[i].dev = device_add_child(dev, typestr, childunit);
308158124Smarcel		if (sc->sc_ports[i].dev == NULL) {
30990731Sjhay			if (sc->barmuxed) {
310158124Smarcel				bus_space_unmap(rman_get_bustag(rle->res),
311158124Smarcel				    rman_get_bushandle(rle->res), 8);
312158124Smarcel				free(rle->res, M_DEVBUF);
313158124Smarcel				free(pdev, M_DEVBUF);
314158124Smarcel			}
315158124Smarcel			continue;
316158124Smarcel		}
317158124Smarcel		device_set_ivars(sc->sc_ports[i].dev, pdev);
318158124Smarcel		device_set_desc(sc->sc_ports[i].dev, sc->sc_desc->name);
319158124Smarcel		if (!bootverbose)
320158124Smarcel			device_quiet(sc->sc_ports[i].dev);
321158124Smarcel#ifdef PUC_DEBUG
32290731Sjhay		printf("puc: type %d, bar %x, offset %x\n",
323158124Smarcel		    sc->sc_desc->ports[i].type,
324158124Smarcel		    sc->sc_desc->ports[i].bar,
325158124Smarcel		    sc->sc_desc->ports[i].offset);
326158124Smarcel		puc_print_resource_list(&pdev->resources);
327158124Smarcel#endif
32890731Sjhay		device_set_flags(sc->sc_ports[i].dev,
329158124Smarcel		    sc->sc_desc->ports[i].flags);
330158124Smarcel		if (device_probe_and_attach(sc->sc_ports[i].dev) != 0) {
331158124Smarcel			if (sc->barmuxed) {
332158124Smarcel				bus_space_unmap(rman_get_bustag(rle->res),
333158124Smarcel						rman_get_bushandle(rle->res),
33490731Sjhay						8);
335158124Smarcel				free(rle->res, M_DEVBUF);
336158124Smarcel				free(pdev, M_DEVBUF);
337158124Smarcel			}
338158124Smarcel		}
33990731Sjhay	}
340158124Smarcel
341158124Smarcel#ifdef PUC_DEBUG
342158124Smarcel	bootverbose = 0;
343158124Smarcel#endif
34490925Snyan	return (0);
34590731Sjhay}
34690731Sjhay
347158124Smarcelstatic u_int32_t
348158124Smarcelpuc_ilr_read(struct puc_softc *sc)
349158124Smarcel{
350158124Smarcel	u_int32_t mask;
351158124Smarcel	int i;
352158124Smarcel
353158124Smarcel	mask = 0;
35490731Sjhay	switch (sc->sc_desc->ilr_type) {
355158124Smarcel	case PUC_ILR_TYPE_DIGI:
356158124Smarcel		for (i = 1; i >= 0; i--) {
357158124Smarcel			mask = (mask << 8) | (bus_space_read_1(sc->ilr_st,
358158124Smarcel			    sc->ilr_sh, sc->sc_desc->ilr_offset[i]) & 0xff);
359158124Smarcel		}
360158124Smarcel		break;
361158124Smarcel
362158124Smarcel	default:
363158124Smarcel		mask = 0xffffffff;
364158124Smarcel		break;
365158124Smarcel	}
366158124Smarcel	return (mask);
367158124Smarcel}
368158124Smarcel
369158124Smarcel/*
370158124Smarcel * This is an interrupt handler. For boards that can't tell us which
371158124Smarcel * device generated the interrupt it just calls all the registered
372158124Smarcel * handlers sequencially, but for boards that can tell us which
373158124Smarcel * device(s) generated the interrupt it calls only handlers for devices
374158124Smarcel * that actually generated the interrupt.
375158124Smarcel */
376158124Smarcelstatic void
377158124Smarcelpuc_intr(void *arg)
378158124Smarcel{
379158124Smarcel	int i;
38090731Sjhay	u_int32_t ilr_mask;
38190731Sjhay	struct puc_softc *sc;
382158124Smarcel
383158124Smarcel	sc = (struct puc_softc *)arg;
384112270Ssobomax	ilr_mask = sc->ilr_enabled ? puc_ilr_read(sc) : 0xffffffff;
385158124Smarcel	for (i = 0; i < PUC_MAX_PORTS; i++)
386158124Smarcel		if (sc->sc_ports[i].ihand != NULL &&
387158124Smarcel		    ((ilr_mask >> i) & 0x00000001))
388158124Smarcel			(sc->sc_ports[i].ihand)(sc->sc_ports[i].ihandarg);
389112270Ssobomax}
390158124Smarcel
391112270Ssobomaxconst struct puc_device_description *
392158124Smarcelpuc_find_description(uint32_t vend, uint32_t prod, uint32_t svend,
393158124Smarcel    uint32_t sprod)
394158124Smarcel{
395158124Smarcel	int i;
396158124Smarcel
397158124Smarcel#define checkreg(val, index) \
398158124Smarcel    (((val) & puc_devices[i].rmask[(index)]) == puc_devices[i].rval[(index)])
399158124Smarcel
400158124Smarcel	for (i = 0; puc_devices[i].name != NULL; i++) {
401158124Smarcel		if (checkreg(vend, PUC_REG_VEND) &&
402158124Smarcel		    checkreg(prod, PUC_REG_PROD) &&
403158124Smarcel		    checkreg(svend, PUC_REG_SVEND) &&
404158124Smarcel		    checkreg(sprod, PUC_REG_SPROD))
405158124Smarcel			return (&puc_devices[i]);
406112270Ssobomax	}
407158124Smarcel
408158124Smarcel#undef checkreg
409112270Ssobomax
410158124Smarcel	return (NULL);
411158124Smarcel}
412158124Smarcel
41390731Sjhaystatic int
414158124Smarcelpuc_find_free_unit(char *name)
415158124Smarcel{
416158124Smarcel	devclass_t dc;
417158124Smarcel	int start;
418158124Smarcel	int unit;
419158124Smarcel
420158124Smarcel	unit = 0;
421158124Smarcel	start = 0;
422158124Smarcel	while (resource_int_value(name, unit, "port", &start) == 0 &&
423158124Smarcel	    start > 0)
424158124Smarcel		unit++;
425158124Smarcel	dc = devclass_find(name);
426158124Smarcel	if (dc == NULL)
427158124Smarcel		return (-1);
428158124Smarcel	while (devclass_get_device(dc, unit))
42990731Sjhay		unit++;
43090731Sjhay#ifdef PUC_DEBUG
431158124Smarcel	printf("puc: Using %s%d\n", name, unit);
432158124Smarcel#endif
43390731Sjhay	return (unit);
434158124Smarcel}
435158124Smarcel
436158124Smarcel#ifdef PUC_DEBUG
43790731Sjhaystatic void
438158124Smarcelpuc_print_resource_list(struct resource_list *rl)
439158124Smarcel{
440158124Smarcel#if 0
44190731Sjhay	struct resource_list_entry *rle;
442158124Smarcel
443158124Smarcel	printf("print_resource_list: rl %p\n", rl);
444158124Smarcel	SLIST_FOREACH(rle, rl, link)
445158124Smarcel		printf("  type %x, rid %x start %x end %x count %x\n",
446158124Smarcel		    rle->type, rle->rid, rle->start, rle->end, rle->count);
447158124Smarcel	printf("print_resource_list: end.\n");
448158124Smarcel#endif
449158124Smarcel}
450158124Smarcel#endif
451158124Smarcel
452158124Smarcelstruct resource *
453158124Smarcelpuc_alloc_resource(device_t dev, device_t child, int type, int *rid,
45490731Sjhay    u_long start, u_long end, u_long count, u_int flags)
45590731Sjhay{
456102714Sphk	struct puc_device *pdev;
457158124Smarcel	struct resource *retval;
45890731Sjhay	struct resource_list *rl;
45990731Sjhay	struct resource_list_entry *rle;
460158124Smarcel
461158124Smarcel	pdev = device_get_ivars(child);
462158124Smarcel	rl = &pdev->resources;
463158124Smarcel
46490731Sjhay#ifdef PUC_DEBUG
465158124Smarcel	printf("puc_alloc_resource: pdev %p, looking for t %x, r %x\n",
466158124Smarcel	    pdev, type, *rid);
467158124Smarcel	puc_print_resource_list(rl);
468158124Smarcel#endif
469158124Smarcel	retval = NULL;
470158124Smarcel	rle = resource_list_find(rl, type, *rid);
471118292Sambrisko	if (rle) {
472158124Smarcel		start = rle->start;
473158124Smarcel		end = rle->end;
47490731Sjhay		count = rle->count;
475158124Smarcel#ifdef PUC_DEBUG
476158124Smarcel		printf("found rle, %lx, %lx, %lx\n", start, end, count);
477158124Smarcel#endif
478158124Smarcel		retval = rle->res;
479158124Smarcel	} else
480158124Smarcel		printf("oops rle is gone\n");
481158124Smarcel
482158124Smarcel	return (retval);
483158124Smarcel}
484158124Smarcel
485158124Smarcelint
486118292Sambriskopuc_release_resource(device_t dev, device_t child, int type, int rid,
487158124Smarcel    struct resource *res)
48890731Sjhay{
489158124Smarcel	return (0);
490158124Smarcel}
491158124Smarcel
492158124Smarcelint
493158124Smarcelpuc_get_resource(device_t dev, device_t child, int type, int rid,
494158124Smarcel    u_long *startp, u_long *countp)
495158124Smarcel{
496158124Smarcel	struct puc_device *pdev;
497158124Smarcel	struct resource_list *rl;
498158124Smarcel	struct resource_list_entry *rle;
499158124Smarcel
500158124Smarcel	pdev = device_get_ivars(child);
501158124Smarcel	rl = &pdev->resources;
502158124Smarcel
503158124Smarcel#ifdef PUC_DEBUG
504158124Smarcel	printf("puc_get_resource: pdev %p, looking for t %x, r %x\n", pdev,
505158124Smarcel	    type, rid);
506158124Smarcel	puc_print_resource_list(rl);
507158124Smarcel#endif
50890731Sjhay	rle = resource_list_find(rl, type, rid);
50990731Sjhay	if (rle) {
510102714Sphk#ifdef PUC_DEBUG
511158124Smarcel		printf("found rle %p,", rle);
51290731Sjhay#endif
51390731Sjhay		if (startp != NULL)
514158124Smarcel			*startp = rle->start;
515158124Smarcel		if (countp != NULL)
516158124Smarcel			*countp = rle->count;
517158124Smarcel#ifdef PUC_DEBUG
518158124Smarcel		printf(" %lx, %lx\n", rle->start, rle->count);
519158124Smarcel#endif
520158124Smarcel		return (0);
521158124Smarcel	} else
522158124Smarcel		printf("oops rle is gone\n");
523158124Smarcel	return (ENXIO);
524158124Smarcel}
525158124Smarcel
526158124Smarcelint
527158124Smarcelpuc_setup_intr(device_t dev, device_t child, struct resource *r, int flags,
528158124Smarcel	       void (*ihand)(void *), void *arg, void **cookiep)
529158124Smarcel{
530158124Smarcel	int i;
531158124Smarcel	struct puc_softc *sc;
532158124Smarcel
533158124Smarcel	sc = (struct puc_softc *)device_get_softc(dev);
534158124Smarcel	if ((flags & INTR_FAST) != sc->fastintr)
535158124Smarcel		return (ENXIO);
536158124Smarcel	for (i = 0; PUC_PORT_VALID(sc->sc_desc, i); i++) {
537158124Smarcel		if (sc->sc_ports[i].dev == child) {
538158124Smarcel			if (sc->sc_ports[i].ihand != 0)
539158124Smarcel				return (ENXIO);
540158124Smarcel			sc->sc_ports[i].ihand = ihand;
541158124Smarcel			sc->sc_ports[i].ihandarg = arg;
542158124Smarcel			*cookiep = arg;
543158124Smarcel			return (0);
544158124Smarcel		}
545158124Smarcel	}
54690731Sjhay	return (ENXIO);
54790731Sjhay}
54890731Sjhay
549102714Sphkint
550158124Smarcelpuc_teardown_intr(device_t dev, device_t child, struct resource *r,
55190731Sjhay		  void *cookie)
55290731Sjhay{
553158124Smarcel	int i;
554158124Smarcel	struct puc_softc *sc;
555158124Smarcel
55690731Sjhay	sc = (struct puc_softc *)device_get_softc(dev);
557158124Smarcel	for (i = 0; PUC_PORT_VALID(sc->sc_desc, i); i++) {
558158124Smarcel		if (sc->sc_ports[i].dev == child) {
559158124Smarcel			sc->sc_ports[i].ihand = NULL;
560158124Smarcel			sc->sc_ports[i].ihandarg = NULL;
561158124Smarcel			return (0);
56290731Sjhay		}
563158124Smarcel	}
564158124Smarcel	return (ENXIO);
565158124Smarcel}
566158124Smarcel
567158124Smarcelint
568158124Smarcelpuc_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
569158124Smarcel{
570158124Smarcel	struct puc_device *pdev;
571158124Smarcel
572158124Smarcel	pdev = device_get_ivars(child);
573158124Smarcel	if (pdev == NULL)
574158124Smarcel		return (ENOENT);
575158124Smarcel
576158124Smarcel	switch(index) {
577158124Smarcel	case PUC_IVAR_FREQ:
578158124Smarcel		*result = pdev->serialfreq;
579158124Smarcel		break;
580158124Smarcel	default:
581158124Smarcel		return (ENOENT);
58290731Sjhay	}
58390731Sjhay	return (0);
584102714Sphk}
585158124Smarcel