pcii.c revision 150525
1234353Sdim/*-
2203954Srdivacky * Copyright (c) 2005 Poul-Henning Kamp <phk@FreeBSD.org>
3203954Srdivacky * All rights reserved.
4203954Srdivacky *
5203954Srdivacky * Redistribution and use in source and binary forms, with or without
6203954Srdivacky * modification, are permitted provided that the following conditions
7234353Sdim * are met:
8203954Srdivacky * 1. Redistributions of source code must retain the above copyright
9203954Srdivacky *    notice, this list of conditions and the following disclaimer.
10203954Srdivacky * 2. Redistributions in binary form must reproduce the above copyright
11203954Srdivacky *    notice, this list of conditions and the following disclaimer in the
12203954Srdivacky *    documentation and/or other materials provided with the distribution.
13203954Srdivacky *
14203954Srdivacky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15203954Srdivacky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16203954Srdivacky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17203954Srdivacky * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18218893Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19218893Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20203954Srdivacky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21203954Srdivacky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22210299Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23210299Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24210299Sed * SUCH DAMAGE.
25210299Sed *
26210299Sed * Driver for GPIB cards based on NEC �PD7210 and compatibles.
27210299Sed *
28210299Sed * This driver just hooks up to the hardware and leaves all the interesting
29210299Sed * stuff to upd7210.c.
30210299Sed *
31210299Sed * Supported hardware:
32210299Sed *    PCIIA compatible cards.
33210299Sed *
34210299Sed *    Tested and known working:
35210299Sed *	"B&C Microsystems PC488A-0"
36210299Sed *
37210299Sed */
38210299Sed
39210299Sed#include <sys/cdefs.h>
40210299Sed__FBSDID("$FreeBSD: head/sys/dev/ieee488/pcii.c 150525 2005-09-24 20:44:55Z phk $");
41223017Sdim
42226633Sdim#include <sys/param.h>
43226633Sdim#include <sys/systm.h>
44234353Sdim#include <sys/lock.h>
45234353Sdim#include <sys/mutex.h>
46210299Sed#include <sys/kernel.h>
47210299Sed#include <sys/module.h>
48223017Sdim#include <sys/bus.h>
49223017Sdim#include <machine/bus.h>
50210299Sed#include <machine/resource.h>
51234353Sdim#include <sys/rman.h>
52210299Sed#include <isa/isavar.h>
53224145Sdim
54224145Sdim#define UPD7210_HW_DRIVER
55218893Sdim#include <dev/ieee488/upd7210.h>
56234353Sdim
57234353Sdimstruct pcii_softc {
58218893Sdim	int foo;
59210299Sed	struct resource	*res[2];
60210299Sed	struct resource	*dma;
61210299Sed	void *intr_handler;
62210299Sed	struct upd7210	upd7210;
63210299Sed};
64210299Sed
65210299Sedstatic devclass_t pcii_devclass;
66210299Sed
67210299Sedstatic int	pcii_probe(device_t dev);
68210299Sedstatic int	pcii_attach(device_t dev);
69210299Sed
70210299Sedstatic device_method_t pcii_methods[] = {
71210299Sed	DEVMETHOD(device_probe,		pcii_probe),
72210299Sed	DEVMETHOD(device_attach,	pcii_attach),
73210299Sed	DEVMETHOD(device_suspend,	bus_generic_suspend),
74234353Sdim	DEVMETHOD(device_resume,	bus_generic_resume),
75234353Sdim
76234353Sdim	{ 0, 0 }
77210299Sed};
78218893Sdim
79234353Sdimstatic struct resource_spec pcii_res_spec[] = {
80234353Sdim	{ SYS_RES_IRQ,		0, RF_ACTIVE | RF_SHAREABLE},
81234353Sdim	{ SYS_RES_DRQ,		0, RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL},
82234353Sdim	{ SYS_RES_IOPORT,	0, RF_ACTIVE},
83234353Sdim	{ -1, 0, 0 }
84210299Sed};
85234353Sdim
86234353Sdimstatic driver_t pcii_driver = {
87234353Sdim	"pcii",
88234353Sdim	pcii_methods,
89234353Sdim	sizeof(struct pcii_softc),
90234353Sdim};
91234353Sdim
92234353Sdimstatic int
93234353Sdimpcii_probe(device_t dev)
94234353Sdim{
95234353Sdim	int rid, i, j;
96234353Sdim	u_long start, count;
97234353Sdim	int error = 0;
98234353Sdim	struct pcii_softc *sc;
99210299Sed
100212904Sdim	device_set_desc(dev, "PCII IEEE-4888 controller");
101212904Sdim	sc = device_get_softc(dev);
102210299Sed
103212904Sdim	rid = 0;
104210299Sed	if (bus_get_resource(dev, SYS_RES_IOPORT, rid, &start, &count) != 0)
105234353Sdim		return ENXIO;
106234353Sdim	if ((start & 0x3ff) != 0x2e1)
107234353Sdim		return (ENXIO);
108234353Sdim	count = 1;
109234353Sdim	if (bus_set_resource(dev, SYS_RES_IOPORT, rid, start, count) != 0)
110234353Sdim		return ENXIO;
111234353Sdim	error = bus_alloc_resources(dev, pcii_res_spec, sc->res);
112234353Sdim	if (error)
113234353Sdim		return (error);
114234353Sdim	error = ENXIO;
115234353Sdim	for (i = 0; i < 8; i++) {
116212904Sdim		j = bus_read_1(sc->res[2], i * 0x400);
117212904Sdim		if (j != 0x00 && j != 0xff)
118212904Sdim			error = 0;
119212904Sdim	}
120212904Sdim	if (!error) {
121212904Sdim		bus_write_1(sc->res[2], 3 * 0x400, 0x55);
122212904Sdim		if (bus_read_1(sc->res[2], 3 * 0x400) != 0x55)
123212904Sdim			error = ENXIO;
124212904Sdim	}
125212904Sdim	if (!error) {
126212904Sdim		bus_write_1(sc->res[2], 3 * 0x400, 0xaa);
127212904Sdim		if (bus_read_1(sc->res[2], 3 * 0x400) != 0xaa)
128226633Sdim			error = ENXIO;
129234353Sdim	}
130234353Sdim	bus_release_resources(dev, pcii_res_spec, sc->res);
131226633Sdim	return (error);
132212904Sdim}
133212904Sdim
134212904Sdimstatic int
135212904Sdimpcii_attach(device_t dev)
136212904Sdim{
137212904Sdim	struct pcii_softc *sc;
138234353Sdim	int		unit;
139212904Sdim	int		rid;
140212904Sdim	int		error = 0;
141212904Sdim
142212904Sdim	unit = device_get_unit(dev);
143212904Sdim	sc = device_get_softc(dev);
144212904Sdim	memset(sc, 0, sizeof *sc);
145212904Sdim
146212904Sdim	device_set_desc(dev, "PCII IEEE-4888 controller");
147212904Sdim
148212904Sdim	error = bus_alloc_resources(dev, pcii_res_spec, sc->res);
149212904Sdim	if (error)
150212904Sdim		return (error);
151212904Sdim
152212904Sdim	error = bus_setup_intr(dev, sc->res[0],
153212904Sdim	    INTR_TYPE_MISC | INTR_MPSAFE,
154234353Sdim	    upd7210intr, &sc->upd7210, &sc->intr_handler);
155234353Sdim	if (error) {
156212904Sdim		bus_release_resources(dev, pcii_res_spec, sc->res);
157234353Sdim		return (error);
158226633Sdim	}
159234353Sdim
160212904Sdim	for (rid = 0; rid < 8; rid++) {
161234353Sdim		sc->upd7210.reg_res[rid] = sc->res[2];
162212904Sdim		sc->upd7210.reg_offset[rid] = 0x400 * rid;
163234353Sdim	}
164234353Sdim
165234353Sdim	if (sc->res[1] == NULL)
166226633Sdim		sc->upd7210.dmachan = -1;
167210299Sed	else
168210299Sed		sc->upd7210.dmachan = rman_get_start(sc->res[1]);
169210299Sed
170210299Sed	upd7210attach(&sc->upd7210);
171210299Sed	return (error);
172210299Sed}
173210299Sed
174210299SedDRIVER_MODULE(pcii, isa, pcii_driver, pcii_devclass, 0, 0);
175218893SdimDRIVER_MODULE(pcii, acpi, pcii_driver, pcii_devclass, 0, 0);
176218893Sdim