pcii.c revision 141423
1/*-
2 * Copyright (c) 2005 Poul-Henning Kamp <phk@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * Driver for GPIB cards based on NEC �PD7210 and compatibles.
27 *
28 * This driver just hooks up to the hardware and leaves all the interesting
29 * stuff to upd7210.c.
30 *
31 * Supported hardware:
32 *    PCIIA compatible cards.
33 *
34 *    Tested and known working:
35 *	"B&C Microsystems PC488A-0"
36 *
37 */
38
39#include <sys/cdefs.h>
40__FBSDID("$FreeBSD: head/sys/dev/ieee488/pcii.c 141423 2005-02-06 22:45:12Z phk $");
41
42#include <sys/param.h>
43#include <sys/systm.h>
44#include <sys/lock.h>
45#include <sys/mutex.h>
46#include <sys/kernel.h>
47#include <sys/module.h>
48#include <sys/bus.h>
49#include <machine/bus.h>
50#include <machine/resource.h>
51#include <sys/rman.h>
52#include <isa/isavar.h>
53
54#include <dev/ieee488/upd7210.h>
55
56struct pcii_softc {
57	int foo;
58	struct resource	*port[8];
59	struct resource	*irq;
60	struct resource	*dma;
61	void *intr_handler;
62	struct upd7210	upd7210;
63};
64
65static devclass_t pcii_devclass;
66
67static int	pcii_probe(device_t dev);
68static int	pcii_attach(device_t dev);
69
70static device_method_t pcii_methods[] = {
71	DEVMETHOD(device_probe,		pcii_probe),
72	DEVMETHOD(device_attach,	pcii_attach),
73	DEVMETHOD(device_suspend,	bus_generic_suspend),
74	DEVMETHOD(device_resume,	bus_generic_resume),
75
76	{ 0, 0 }
77};
78
79static driver_t pcii_driver = {
80	"pcii",
81	pcii_methods,
82	sizeof(struct pcii_softc),
83};
84
85static int
86pcii_probe(device_t dev)
87{
88	struct resource	*port;
89	int rid;
90	u_long start, count;
91	int i, j, error = 0;
92
93	device_set_desc(dev, "PCII IEEE-4888 controller");
94
95	rid = 0;
96	if (bus_get_resource(dev, SYS_RES_IOPORT, rid, &start, &count) != 0)
97		return ENXIO;
98	if ((start & 0x3ff) != 0x2e1)
99		return (ENXIO);
100	count = 1;
101	if (bus_set_resource(dev, SYS_RES_IOPORT, rid, start, count) != 0)
102		return ENXIO;
103	for (i = 0; i < 8; i++) {
104		j = bus_set_resource(dev, SYS_RES_IOPORT, i,
105		    start + 0x400 * i, 1);
106		if (j) {
107			error = ENXIO;
108			break;
109		}
110		rid = i;
111		port = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
112		    &rid, RF_ACTIVE);
113		if (port == NULL)
114			return (ENXIO);
115		else
116			bus_release_resource(dev, SYS_RES_IOPORT, i, port);
117	}
118
119	rid = 0;
120	port = bus_alloc_resource_any(dev,
121	    SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE);
122	if (port == NULL)
123		return (ENXIO);
124	bus_release_resource(dev, SYS_RES_IRQ, rid, port);
125
126	return (error);
127}
128
129static int
130pcii_attach(device_t dev)
131{
132	struct pcii_softc *sc;
133	int		unit;
134	int		rid;
135	int i, error = 0;
136
137	unit = device_get_unit(dev);
138	sc = device_get_softc(dev);
139	memset(sc, 0, sizeof *sc);
140
141	device_set_desc(dev, "PCII IEEE-4888 controller");
142
143	for (rid = 0; rid < 8; rid++) {
144		sc->port[rid] = bus_alloc_resource_any(dev,
145		    SYS_RES_IOPORT, &rid, RF_ACTIVE);
146		if (sc->port[rid] == NULL) {
147			error = ENXIO;
148			break;
149		}
150		sc->upd7210.reg_tag[rid] = rman_get_bustag(sc->port[rid]);
151		sc->upd7210.reg_handle[rid] = rman_get_bushandle(sc->port[rid]);
152	}
153	if (!error) {
154		rid = 0;
155		sc->irq = bus_alloc_resource_any(dev,
156		    SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE);
157		if (sc->irq == NULL) {
158			error = ENXIO;
159		} else {
160			error = bus_setup_intr(dev, sc->irq,
161			    INTR_TYPE_MISC | INTR_MPSAFE,
162			    upd7210intr, &sc->upd7210, &sc->intr_handler);
163		}
164	}
165	if (!error) {
166		rid = 0;
167		sc->dma = bus_alloc_resource_any(dev,
168		    SYS_RES_DRQ, &rid, RF_ACTIVE | RF_SHAREABLE);
169		if (sc->dma == NULL)
170			sc->upd7210.dmachan = -1;
171		else
172			sc->upd7210.dmachan = rman_get_start(sc->dma);
173	}
174	if (error) {
175		for (i = 0; i < 8; i++) {
176			if (sc->port[i] == NULL)
177				break;
178			bus_release_resource(dev, SYS_RES_IOPORT,
179			    0, sc->port[i]);
180		}
181		if (sc->intr_handler != NULL)
182			bus_teardown_intr(dev, sc->irq, sc->intr_handler);
183		if (sc->irq != NULL)
184			bus_release_resource(dev, SYS_RES_IRQ, i, sc->irq);
185	}
186	upd7210attach(&sc->upd7210);
187	return (error);
188}
189
190DRIVER_MODULE(pcii, isa, pcii_driver, pcii_devclass, 0, 0);
191DRIVER_MODULE(pcii, acpi, pcii_driver, pcii_devclass, 0, 0);
192