puc.c revision 114344
1189747Ssam/*	$NetBSD: puc.c,v 1.7 2000/07/29 17:43:38 jlam Exp $	*/
2217751Sadrian
3189747Ssam/*-
4189747Ssam * Copyright (c) 2002 JF Hay.  All rights reserved.
5189747Ssam * Copyright (c) 2000 M. Warner Losh.  All rights reserved.
6189747Ssam *
7189747Ssam * Redistribution and use in source and binary forms, with or without
8189747Ssam * modification, are permitted provided that the following conditions
9189747Ssam * are met:
10189747Ssam * 1. Redistributions of source code must retain the above copyright
11189747Ssam *    notice unmodified, this list of conditions, and the following
12189747Ssam *    disclaimer.
13189747Ssam * 2. Redistributions in binary form must reproduce the above copyright
14189747Ssam *    notice, this list of conditions and the following disclaimer in the
15189747Ssam *    documentation and/or other materials provided with the distribution.
16189747Ssam *
17189747Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18189747Ssam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19189747Ssam * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20189747Ssam * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21189747Ssam * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22189747Ssam * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23189747Ssam * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24189747Ssam * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25189747Ssam * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26189747Ssam * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27217751Sadrian */
28217751Sadrian
29189747Ssam/*
30189747Ssam * Copyright (c) 1996, 1998, 1999
31189747Ssam *	Christopher G. Demetriou.  All rights reserved.
32217751Sadrian *
33189747Ssam * Redistribution and use in source and binary forms, with or without
34189747Ssam * modification, are permitted provided that the following conditions
35189747Ssam * are met:
36189747Ssam * 1. Redistributions of source code must retain the above copyright
37189747Ssam *    notice, this list of conditions and the following disclaimer.
38217751Sadrian * 2. Redistributions in binary form must reproduce the above copyright
39189747Ssam *    notice, this list of conditions and the following disclaimer in the
40217751Sadrian *    documentation and/or other materials provided with the distribution.
41189747Ssam * 3. All advertising materials mentioning features or use of this software
42189747Ssam *    must display the following acknowledgement:
43189747Ssam *      This product includes software developed by Christopher G. Demetriou
44189747Ssam *	for the NetBSD Project.
45189747Ssam * 4. The name of the author may not be used to endorse or promote products
46217751Sadrian *    derived from this software without specific prior written permission
47189747Ssam *
48189747Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
49189747Ssam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
50189747Ssam * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
51189747Ssam * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
52217751Sadrian * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
53189747Ssam * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
54189747Ssam * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
55189747Ssam * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
56189747Ssam * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
57189747Ssam * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
58189747Ssam */
59189747Ssam
60189747Ssam#include <sys/cdefs.h>
61217751Sadrian__FBSDID("$FreeBSD: head/sys/dev/puc/puc.c 114344 2003-04-30 22:15:47Z sobomax $");
62189747Ssam
63189747Ssam/*
64217751Sadrian * PCI "universal" communication card device driver, glues com, lpt,
65189747Ssam * and similar ports to PCI via bridge chip often much larger than
66189747Ssam * the devices being glued.
67189747Ssam *
68189747Ssam * Author: Christopher G. Demetriou, May 14, 1998 (derived from NetBSD
69189747Ssam * sys/dev/pci/pciide.c, revision 1.6).
70217751Sadrian *
71189747Ssam * These devices could be (and some times are) described as
72189747Ssam * communications/{serial,parallel}, etc. devices with known
73189747Ssam * programming interfaces, but those programming interfaces (in
74189747Ssam * particular the BAR assignments for devices, etc.) in fact are not
75189747Ssam * particularly well defined.
76189747Ssam *
77189747Ssam * After I/we have seen more of these devices, it may be possible
78189747Ssam * to generalize some of these bits.  In particular, devices which
79189747Ssam * describe themselves as communications/serial/16[45]50, and
80189747Ssam * communications/parallel/??? might be attached via direct
81189747Ssam * 'com' and 'lpt' attachments to pci.
82189747Ssam */
83189747Ssam
84189747Ssam#include "opt_puc.h"
85189747Ssam
86189747Ssam#include <sys/param.h>
87189747Ssam#include <sys/systm.h>
88189747Ssam#include <sys/kernel.h>
89189747Ssam#include <sys/bus.h>
90189747Ssam#include <sys/conf.h>
91189747Ssam#include <sys/malloc.h>
92189747Ssam
93189747Ssam#include <machine/bus.h>
94189747Ssam#include <machine/resource.h>
95189747Ssam#include <sys/rman.h>
96189747Ssam
97189747Ssam#include <dev/pci/pcireg.h>
98189747Ssam#include <dev/pci/pcivar.h>
99189747Ssam
100189747Ssam#define PUC_ENTRAILS	1
101189747Ssam#include <dev/puc/pucvar.h>
102189747Ssam
103189747Ssamstruct puc_device {
104189747Ssam	struct resource_list resources;
105189747Ssam	u_int serialfreq;
106189747Ssam};
107189747Ssam
108189747Ssamstatic void puc_intr(void *arg);
109189747Ssam
110189747Ssamstatic int puc_find_free_unit(char *);
111189747Ssam#ifdef PUC_DEBUG
112189747Ssamstatic void puc_print_resource_list(struct resource_list *);
113189747Ssam#endif
114189747Ssam
115189747Ssamdevclass_t puc_devclass;
116189747Ssam
117189747Ssamstatic int
118189747Ssampuc_port_bar_index(struct puc_softc *sc, int bar)
119189747Ssam{
120189747Ssam	int i;
121189747Ssam
122189747Ssam	for (i = 0; i < PUC_MAX_BAR; i += 1) {
123189747Ssam		if (!sc->sc_bar_mappings[i].used)
124189747Ssam			break;
125189747Ssam		if (sc->sc_bar_mappings[i].bar == bar)
126189747Ssam			return (i);
127189747Ssam	}
128189747Ssam	sc->sc_bar_mappings[i].bar = bar;
129189747Ssam	sc->sc_bar_mappings[i].used = 1;
130189747Ssam	return (i);
131189747Ssam}
132189747Ssam
133189747Ssamstatic int
134189747Ssampuc_probe_ilr(struct puc_softc *sc, struct resource *res)
135189747Ssam{
136189747Ssam	u_char t1, t2;
137189747Ssam	int i;
138189747Ssam
139189747Ssam	switch (sc->sc_desc->ilr_type) {
140189747Ssam	case PUC_ILR_TYPE_DIGI:
141189747Ssam		sc->ilr_st = rman_get_bustag(res);
142189747Ssam		sc->ilr_sh = rman_get_bushandle(res);
143189747Ssam		for (i = 0; i < 2 && sc->sc_desc->ilr_offset[i] != 0; i++) {
144189747Ssam			t1 = bus_space_read_1(sc->ilr_st, sc->ilr_sh,
145189747Ssam			    sc->sc_desc->ilr_offset[i]);
146189747Ssam			t1 = ~t1;
147189747Ssam			bus_space_write_1(sc->ilr_st, sc->ilr_sh,
148189747Ssam			    sc->sc_desc->ilr_offset[i], t1);
149189747Ssam			t2 = bus_space_read_1(sc->ilr_st, sc->ilr_sh,
150189747Ssam			    sc->sc_desc->ilr_offset[i]);
151189747Ssam			if (t2 == t1)
152189747Ssam				return (0);
153189747Ssam		}
154189747Ssam		return (1);
155189747Ssam
156189747Ssam	default:
157189747Ssam		break;
158189747Ssam	}
159189747Ssam	return (0);
160189747Ssam}
161189747Ssam
162189747Ssamint
163189747Ssampuc_attach(device_t dev, const struct puc_device_description *desc)
164189747Ssam{
165189747Ssam	char *typestr;
166189747Ssam	int bidx, childunit, i, irq_setup, rid, type;
167189747Ssam	struct puc_softc *sc;
168189747Ssam	struct puc_device *pdev;
169189747Ssam	struct resource *res;
170189747Ssam	struct resource_list_entry *rle;
171189747Ssam
172189747Ssam	sc = (struct puc_softc *)device_get_softc(dev);
173189747Ssam	bzero(sc, sizeof(*sc));
174189747Ssam	sc->sc_desc = desc;
175189747Ssam	if (sc->sc_desc == NULL)
176189747Ssam		return (ENXIO);
177189747Ssam
178189747Ssam#ifdef PUC_DEBUG
179189747Ssam	bootverbose = 1;
180189747Ssam
181189747Ssam	printf("puc: name: %s\n", sc->sc_desc->name);
182189747Ssam#endif
183189747Ssam	rid = 0;
184189747Ssam	res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
185189747Ssam	    RF_ACTIVE | RF_SHAREABLE);
186189747Ssam	if (!res)
187189747Ssam		return (ENXIO);
188189747Ssam
189189747Ssam	sc->irqres = res;
190189747Ssam	sc->irqrid = rid;
191189747Ssam#ifdef PUC_FASTINTR
192189747Ssam	irq_setup = BUS_SETUP_INTR(device_get_parent(dev), dev, res,
193189747Ssam	    INTR_TYPE_TTY | INTR_FAST, puc_intr, sc, &sc->intr_cookie);
194189747Ssam	if (irq_setup == 0)
195189747Ssam		sc->fastintr = INTR_FAST;
196189747Ssam	else
197189747Ssam		irq_setup = BUS_SETUP_INTR(device_get_parent(dev), dev, res,
198189747Ssam		    INTR_TYPE_TTY, puc_intr, sc, &sc->intr_cookie);
199189747Ssam#else
200189747Ssam	irq_setup = BUS_SETUP_INTR(device_get_parent(dev), dev, res,
201189747Ssam	    INTR_TYPE_TTY, puc_intr, sc, &sc->intr_cookie);
202189747Ssam#endif
203189747Ssam	if (irq_setup != 0)
204189747Ssam		return (ENXIO);
205189747Ssam
206189747Ssam	rid = 0;
207189747Ssam	for (i = 0; PUC_PORT_VALID(sc->sc_desc, i); i++) {
208189747Ssam		if (i > 0 && rid == sc->sc_desc->ports[i].bar)
209189747Ssam			sc->barmuxed = 1;
210189747Ssam		rid = sc->sc_desc->ports[i].bar;
211189747Ssam		bidx = puc_port_bar_index(sc, rid);
212189747Ssam
213189747Ssam		if (sc->sc_bar_mappings[bidx].res != NULL)
214189747Ssam			continue;
215189747Ssam
216189747Ssam		type = (sc->sc_desc->ports[i].flags & PUC_FLAGS_MEMORY)
217189747Ssam		    ? SYS_RES_MEMORY : SYS_RES_IOPORT;
218189747Ssam
219189747Ssam		res = bus_alloc_resource(dev, type, &rid, 0ul, ~0ul, 1,
220189747Ssam		    RF_ACTIVE);
221189747Ssam		if (res == NULL) {
222189747Ssam			printf("could not get resource\n");
223189747Ssam			continue;
224189747Ssam		}
225189747Ssam		sc->sc_bar_mappings[bidx].type = type;
226189747Ssam		sc->sc_bar_mappings[bidx].res = res;
227189747Ssam
228189747Ssam		if (sc->sc_desc->ilr_type != PUC_ILR_TYPE_NONE) {
229189747Ssam			sc->ilr_enabled = puc_probe_ilr(sc, res);
230189747Ssam			if (sc->ilr_enabled)
231189747Ssam				device_printf(dev, "ILR enabled\n");
232189747Ssam			else
233189747Ssam				device_printf(dev, "ILR disabled\n");
234189747Ssam		}
235189747Ssam#ifdef PUC_DEBUG
236189747Ssam		printf("%s rid %d bst %x, start %x, end %x\n",
237189747Ssam		    (type == SYS_RES_MEMORY) ? "memory" : "port", rid,
238189747Ssam		    (u_int)rman_get_bustag(res), (u_int)rman_get_start(res),
239189747Ssam		    (u_int)rman_get_end(res));
240189747Ssam#endif
241217751Sadrian	}
242189747Ssam
243189747Ssam	if (desc->init != NULL) {
244189747Ssam		i = desc->init(sc);
245189747Ssam		if (i != 0)
246189747Ssam			return (i);
247189747Ssam	}
248189747Ssam
249189747Ssam	for (i = 0; PUC_PORT_VALID(sc->sc_desc, i); i++) {
250189747Ssam		rid = sc->sc_desc->ports[i].bar;
251189747Ssam		bidx = puc_port_bar_index(sc, rid);
252189747Ssam		if (sc->sc_bar_mappings[bidx].res == NULL)
253189747Ssam			continue;
254189747Ssam
255189747Ssam		switch (sc->sc_desc->ports[i].type) {
256189747Ssam		case PUC_PORT_TYPE_COM:
257189747Ssam			typestr = "sio";
258189747Ssam			break;
259189747Ssam		default:
260189747Ssam			continue;
261217751Sadrian		}
262189747Ssam		pdev = malloc(sizeof(struct puc_device), M_DEVBUF,
263189747Ssam		    M_NOWAIT | M_ZERO);
264189747Ssam		if (!pdev)
265189747Ssam			continue;
266189747Ssam		resource_list_init(&pdev->resources);
267189747Ssam
268189747Ssam		/* First fake up an IRQ resource. */
269189747Ssam		resource_list_add(&pdev->resources, SYS_RES_IRQ, 0,
270189747Ssam		    rman_get_start(sc->irqres), rman_get_end(sc->irqres),
271189747Ssam		    rman_get_end(sc->irqres) - rman_get_start(sc->irqres) + 1);
272189747Ssam		rle = resource_list_find(&pdev->resources, SYS_RES_IRQ, 0);
273189747Ssam		rle->res = sc->irqres;
274189747Ssam
275189747Ssam		/* Now fake an IOPORT or MEMORY resource */
276189747Ssam		res = sc->sc_bar_mappings[bidx].res;
277189747Ssam		type = sc->sc_bar_mappings[bidx].type;
278189747Ssam		resource_list_add(&pdev->resources, type, 0,
279189747Ssam		    rman_get_start(res) + sc->sc_desc->ports[i].offset,
280189747Ssam		    rman_get_start(res) + sc->sc_desc->ports[i].offset + 8 - 1,
281189747Ssam		    8);
282189747Ssam		rle = resource_list_find(&pdev->resources, type, 0);
283189747Ssam
284189747Ssam		if (sc->barmuxed == 0) {
285189747Ssam			rle->res = sc->sc_bar_mappings[bidx].res;
286189747Ssam		} else {
287189747Ssam			rle->res = malloc(sizeof(struct resource), M_DEVBUF,
288189747Ssam			    M_WAITOK | M_ZERO);
289189747Ssam			if (rle->res == NULL) {
290189747Ssam				free(pdev, M_DEVBUF);
291189747Ssam				return (ENOMEM);
292217751Sadrian			}
293189747Ssam
294189747Ssam			rle->res->r_start = rman_get_start(res) +
295189747Ssam			    sc->sc_desc->ports[i].offset;
296189747Ssam			rle->res->r_end = rle->res->r_start + 8 - 1;
297189747Ssam			rle->res->r_bustag = rman_get_bustag(res);
298189747Ssam			bus_space_subregion(rle->res->r_bustag,
299189747Ssam			    rman_get_bushandle(res),
300189747Ssam			    sc->sc_desc->ports[i].offset, 8,
301189747Ssam			    &rle->res->r_bushandle);
302189747Ssam		}
303189747Ssam
304189747Ssam		pdev->serialfreq = sc->sc_desc->ports[i].serialfreq;
305189747Ssam
306189747Ssam		childunit = puc_find_free_unit(typestr);
307189747Ssam		sc->sc_ports[i].dev = device_add_child(dev, typestr, childunit);
308189747Ssam		if (sc->sc_ports[i].dev == NULL) {
309189747Ssam			if (sc->barmuxed) {
310217751Sadrian				bus_space_unmap(rman_get_bustag(rle->res),
311217751Sadrian				    rman_get_bushandle(rle->res), 8);
312217751Sadrian				free(rle->res, M_DEVBUF);
313217751Sadrian				free(pdev, M_DEVBUF);
314217751Sadrian			}
315217751Sadrian			continue;
316189747Ssam		}
317189747Ssam		device_set_ivars(sc->sc_ports[i].dev, pdev);
318189747Ssam		device_set_desc(sc->sc_ports[i].dev, sc->sc_desc->name);
319189747Ssam		if (!bootverbose)
320189747Ssam			device_quiet(sc->sc_ports[i].dev);
321189747Ssam#ifdef PUC_DEBUG
322189747Ssam		printf("puc: type %d, bar %x, offset %x\n",
323189747Ssam		    sc->sc_desc->ports[i].type,
324189747Ssam		    sc->sc_desc->ports[i].bar,
325189747Ssam		    sc->sc_desc->ports[i].offset);
326189747Ssam		puc_print_resource_list(&pdev->resources);
327189747Ssam#endif
328189747Ssam		device_set_flags(sc->sc_ports[i].dev,
329189747Ssam		    sc->sc_desc->ports[i].flags);
330189747Ssam		if (device_probe_and_attach(sc->sc_ports[i].dev) != 0) {
331189747Ssam			if (sc->barmuxed) {
332189747Ssam				bus_space_unmap(rman_get_bustag(rle->res),
333189747Ssam						rman_get_bushandle(rle->res),
334189747Ssam						8);
335189747Ssam				free(rle->res, M_DEVBUF);
336189747Ssam				free(pdev, M_DEVBUF);
337189747Ssam			}
338189747Ssam		}
339189747Ssam	}
340189747Ssam
341189747Ssam#ifdef PUC_DEBUG
342217751Sadrian	bootverbose = 0;
343217751Sadrian#endif
344189747Ssam	return (0);
345189747Ssam}
346189747Ssam
347189747Ssamstatic u_int32_t
348189747Ssampuc_ilr_read(struct puc_softc *sc)
349189747Ssam{
350189747Ssam	u_int32_t mask;
351189747Ssam	int i;
352189747Ssam
353189747Ssam	mask = 0;
354189747Ssam	switch (sc->sc_desc->ilr_type) {
355189747Ssam	case PUC_ILR_TYPE_DIGI:
356189747Ssam		for (i = 1; i >= 0 && sc->sc_desc->ilr_offset[i] != 0; i--) {
357189747Ssam			mask = (mask << 8) | (bus_space_read_1(sc->ilr_st,
358189747Ssam			    sc->ilr_sh, sc->sc_desc->ilr_offset[i]) & 0xff);
359189747Ssam		}
360189747Ssam		break;
361189747Ssam
362189747Ssam	default:
363189747Ssam		mask = 0xffffffff;
364189747Ssam		break;
365189747Ssam	}
366189747Ssam	return (mask);
367189747Ssam}
368189747Ssam
369189747Ssam/*
370189747Ssam * This is an interrupt handler. For boards that can't tell us which
371189747Ssam * device generated the interrupt it just calls all the registered
372189747Ssam * handlers sequencially, but for boards that can tell us which
373189747Ssam * device(s) generated the interrupt it calls only handlers for devices
374189747Ssam * that actually generated the interrupt.
375189747Ssam */
376189747Ssamstatic void
377189747Ssampuc_intr(void *arg)
378189747Ssam{
379189747Ssam	int i;
380189747Ssam	u_int32_t ilr_mask;
381189747Ssam	struct puc_softc *sc;
382189747Ssam
383189747Ssam	sc = (struct puc_softc *)arg;
384189747Ssam	ilr_mask = sc->ilr_enabled ? puc_ilr_read(sc) : 0xffffffff;
385189747Ssam	for (i = 0; i < PUC_MAX_PORTS; i++)
386189747Ssam		if (sc->sc_ports[i].ihand != NULL &&
387189747Ssam		    ((ilr_mask >> i) & 0x00000001))
388189747Ssam			(sc->sc_ports[i].ihand)(sc->sc_ports[i].ihandarg);
389189747Ssam}
390189747Ssam
391189747Ssamconst struct puc_device_description *
392189747Ssampuc_find_description(uint32_t vend, uint32_t prod, uint32_t svend,
393189747Ssam    uint32_t sprod)
394189747Ssam{
395189747Ssam	int i;
396189747Ssam
397189747Ssam#define checkreg(val, index) \
398189747Ssam    (((val) & puc_devices[i].rmask[(index)]) == puc_devices[i].rval[(index)])
399189747Ssam
400189747Ssam	for (i = 0; puc_devices[i].name != NULL; i++) {
401189747Ssam		if (checkreg(vend, PUC_REG_VEND) &&
402189747Ssam		    checkreg(prod, PUC_REG_PROD) &&
403189747Ssam		    checkreg(svend, PUC_REG_SVEND) &&
404189747Ssam		    checkreg(sprod, PUC_REG_SPROD))
405189747Ssam			return (&puc_devices[i]);
406189747Ssam	}
407189747Ssam
408189747Ssam#undef checkreg
409189747Ssam
410189747Ssam	return (NULL);
411189747Ssam}
412189747Ssam
413189747Ssamstatic int
414217751Sadrianpuc_find_free_unit(char *name)
415189747Ssam{
416189747Ssam	devclass_t dc;
417189747Ssam	int start;
418189747Ssam	int unit;
419189747Ssam
420189747Ssam	unit = 0;
421189747Ssam	start = 0;
422217751Sadrian	while (resource_int_value(name, unit, "port", &start) == 0 &&
423189747Ssam	    start > 0)
424189747Ssam		unit++;
425189747Ssam	dc = devclass_find(name);
426189747Ssam	if (dc == NULL)
427189747Ssam		return (-1);
428189747Ssam	while (devclass_get_device(dc, unit))
429189747Ssam		unit++;
430189747Ssam#ifdef PUC_DEBUG
431189747Ssam	printf("puc: Using %s%d\n", name, unit);
432189747Ssam#endif
433189747Ssam	return (unit);
434189747Ssam}
435189747Ssam
436189747Ssam#ifdef PUC_DEBUG
437189747Ssamstatic void
438189747Ssampuc_print_resource_list(struct resource_list *rl)
439189747Ssam{
440189747Ssam#if 0
441189747Ssam	struct resource_list_entry *rle;
442189747Ssam
443189747Ssam	printf("print_resource_list: rl %p\n", rl);
444189747Ssam	SLIST_FOREACH(rle, rl, link)
445189747Ssam		printf("  type %x, rid %x start %x end %x count %x\n",
446189747Ssam		    rle->type, rle->rid, rle->start, rle->end, rle->count);
447189747Ssam	printf("print_resource_list: end.\n");
448189747Ssam#endif
449189747Ssam}
450189747Ssam#endif
451189747Ssam
452189747Ssamstruct resource *
453189747Ssampuc_alloc_resource(device_t dev, device_t child, int type, int *rid,
454189747Ssam    u_long start, u_long end, u_long count, u_int flags)
455189747Ssam{
456189747Ssam	struct puc_device *pdev;
457189747Ssam	struct resource *retval;
458189747Ssam	struct resource_list *rl;
459189747Ssam	struct resource_list_entry *rle;
460189747Ssam
461189747Ssam	pdev = device_get_ivars(child);
462189747Ssam	rl = &pdev->resources;
463189747Ssam
464189747Ssam#ifdef PUC_DEBUG
465189747Ssam	printf("puc_alloc_resource: pdev %p, looking for t %x, r %x\n",
466189747Ssam	    pdev, type, *rid);
467189747Ssam	puc_print_resource_list(rl);
468189747Ssam#endif
469189747Ssam	retval = NULL;
470189747Ssam	rle = resource_list_find(rl, type, *rid);
471189747Ssam	if (rle) {
472189747Ssam		start = rle->start;
473189747Ssam		end = rle->end;
474189747Ssam		count = rle->count;
475189747Ssam#ifdef PUC_DEBUG
476189747Ssam		printf("found rle, %lx, %lx, %lx\n", start, end, count);
477189747Ssam#endif
478189747Ssam		retval = rle->res;
479189747Ssam	} else
480189747Ssam		printf("oops rle is gone\n");
481217751Sadrian
482217751Sadrian	return (retval);
483217751Sadrian}
484217751Sadrian
485217751Sadrianint
486217751Sadrianpuc_release_resource(device_t dev, device_t child, int type, int rid,
487217751Sadrian    struct resource *res)
488217751Sadrian{
489217751Sadrian	return (0);
490217751Sadrian}
491217751Sadrian
492217751Sadrianint
493217751Sadrianpuc_get_resource(device_t dev, device_t child, int type, int rid,
494217751Sadrian    u_long *startp, u_long *countp)
495217751Sadrian{
496217751Sadrian	struct puc_device *pdev;
497217751Sadrian	struct resource_list *rl;
498217751Sadrian	struct resource_list_entry *rle;
499217751Sadrian
500217751Sadrian	pdev = device_get_ivars(child);
501217751Sadrian	rl = &pdev->resources;
502217751Sadrian
503217751Sadrian#ifdef PUC_DEBUG
504217751Sadrian	printf("puc_get_resource: pdev %p, looking for t %x, r %x\n", pdev,
505217751Sadrian	    type, rid);
506217751Sadrian	puc_print_resource_list(rl);
507217751Sadrian#endif
508217751Sadrian	rle = resource_list_find(rl, type, rid);
509217751Sadrian	if (rle) {
510217751Sadrian#ifdef PUC_DEBUG
511217751Sadrian		printf("found rle %p,", rle);
512217751Sadrian#endif
513217751Sadrian		if (startp != NULL)
514217751Sadrian			*startp = rle->start;
515217751Sadrian		if (countp != NULL)
516217751Sadrian			*countp = rle->count;
517217751Sadrian#ifdef PUC_DEBUG
518217751Sadrian		printf(" %lx, %lx\n", rle->start, rle->count);
519217751Sadrian#endif
520217751Sadrian		return (0);
521217751Sadrian	} else
522217751Sadrian		printf("oops rle is gone\n");
523217751Sadrian	return (ENXIO);
524217751Sadrian}
525217751Sadrian
526217751Sadrianint
527217751Sadrianpuc_setup_intr(device_t dev, device_t child, struct resource *r, int flags,
528217751Sadrian	       void (*ihand)(void *), void *arg, void **cookiep)
529217751Sadrian{
530217751Sadrian	int i;
531217751Sadrian	struct puc_softc *sc;
532217751Sadrian
533217751Sadrian	sc = (struct puc_softc *)device_get_softc(dev);
534217751Sadrian	if ((flags & INTR_FAST) != sc->fastintr)
535217751Sadrian		return (ENXIO);
536217751Sadrian	for (i = 0; PUC_PORT_VALID(sc->sc_desc, i); i++) {
537217751Sadrian		if (sc->sc_ports[i].dev == child) {
538217751Sadrian			if (sc->sc_ports[i].ihand != 0)
539217751Sadrian				return (ENXIO);
540217751Sadrian			sc->sc_ports[i].ihand = ihand;
541217751Sadrian			sc->sc_ports[i].ihandarg = arg;
542217751Sadrian			*cookiep = arg;
543217751Sadrian			return (0);
544217751Sadrian		}
545217751Sadrian	}
546217751Sadrian	return (ENXIO);
547217751Sadrian}
548217751Sadrian
549217751Sadrianint
550217751Sadrianpuc_teardown_intr(device_t dev, device_t child, struct resource *r,
551217751Sadrian		  void *cookie)
552217751Sadrian{
553217751Sadrian	int i;
554217751Sadrian	struct puc_softc *sc;
555217751Sadrian
556217751Sadrian	sc = (struct puc_softc *)device_get_softc(dev);
557217751Sadrian	for (i = 0; PUC_PORT_VALID(sc->sc_desc, i); i++) {
558217751Sadrian		if (sc->sc_ports[i].dev == child) {
559217751Sadrian			sc->sc_ports[i].ihand = NULL;
560217751Sadrian			sc->sc_ports[i].ihandarg = NULL;
561217751Sadrian			return (0);
562189747Ssam		}
563189747Ssam	}
564189747Ssam	return (ENXIO);
565189747Ssam}
566217751Sadrian
567217751Sadrianint
568217751Sadrianpuc_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
569217751Sadrian{
570217751Sadrian	struct puc_device *pdev;
571189747Ssam
572189747Ssam	pdev = device_get_ivars(child);
573189747Ssam	if (pdev == NULL)
574189747Ssam		return (ENOENT);
575189747Ssam
576189747Ssam	switch(index) {
577189747Ssam	case PUC_IVAR_FREQ:
578189747Ssam		*result = pdev->serialfreq;
579189747Ssam		break;
580189747Ssam	default:
581189747Ssam		return (ENOENT);
582189747Ssam	}
583189747Ssam	return (0);
584189747Ssam}
585189747Ssam