adlink.c revision 113094
1/*-
2 * Copyright (c) 2003 Poul-Henning Kamp
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 * 3. The names of the authors may not be used to endorse or promote
14 *    products derived from this software without specific prior written
15 *    permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $FreeBSD: head/sys/dev/adlink/adlink.c 113094 2003-04-04 18:53:04Z phk $
30 */
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/malloc.h>
35#include <sys/kernel.h>
36#include <sys/conf.h>
37#include <sys/bus.h>
38#include <machine/bus.h>
39#include <machine/resource.h>
40#include <sys/rman.h>
41#include <pci/pcireg.h>
42#include <pci/pcivar.h>
43#include <pci_if.h>
44#include <vm/vm.h>
45#include <vm/pmap.h>
46
47/*
48 * We sample one channel (= 16 bits) at 1 msps giving 2Mbyte/sec,
49 * 50 pages will give us about 1/10 second buffering.
50 */
51#define NRING	50
52
53#define IN4(sc, offset) bus_space_read_4(sc->t_io, sc->h_io, offset)
54
55struct info {
56	int			nring;
57	off_t			o_ring;
58};
59
60struct softc {
61	device_t		device;
62	void			*intrhand;
63	struct resource		*r0, *r1, *ri;
64	bus_space_tag_t		t0, t1;
65	bus_space_handle_t	h0, h1;
66	dev_t			dev;
67
68	struct info		*info;
69
70	int			idx;
71	void			*ring[NRING];
72	vm_paddr_t		phys[NRING];
73	int			stat[NRING];
74};
75
76static int
77adlink_open(dev_t dev, int oflags, int devtype, struct thread *td)
78{
79	static int once;
80	struct softc *sc;
81	int i;
82	uint32_t u;
83
84	if (once)
85		return (0);
86	once = 1;
87
88	sc = dev->si_drv1;
89	sc->info = malloc(PAGE_SIZE, M_DEVBUF, M_ZERO | M_WAITOK);
90	sc->info->nring = NRING;
91	sc->info->o_ring = PAGE_SIZE;
92	for (i = 0; i < NRING; i++) {
93		sc->ring[i] = malloc(PAGE_SIZE, M_DEVBUF, M_ZERO | M_WAITOK);
94		sc->phys[i] = vtophys(sc->ring[i]);
95	}
96
97	bus_space_write_4(sc->t0, sc->h0, 0x38, 0x00004000);
98	bus_space_write_4(sc->t1, sc->h1, 0x00, 1);
99	bus_space_write_4(sc->t1, sc->h1, 0x04, 10);
100	bus_space_write_4(sc->t1, sc->h1, 0x08, 0);
101	bus_space_write_4(sc->t1, sc->h1, 0x0c, 0);
102	bus_space_write_4(sc->t1, sc->h1, 0x10, 0);
103	bus_space_write_4(sc->t1, sc->h1, 0x18, 3);
104	bus_space_write_4(sc->t1, sc->h1, 0x20, 2);
105
106	bus_space_write_4(sc->t0, sc->h0, 0x24, sc->phys[i]);
107	bus_space_write_4(sc->t0, sc->h0, 0x28, PAGE_SIZE);
108
109	u = bus_space_read_4(sc->t0, sc->h0, 0x3c);
110	bus_space_write_4(sc->t0, sc->h0, 0x3c, u | 0x00000600);
111
112	bus_space_write_4(sc->t1, sc->h1, 0x1c, 1);
113	return (0);
114}
115
116static int
117adlink_mmap(dev_t dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot)
118{
119	int i;
120	struct softc *sc;
121
122	sc = dev->si_drv1;
123	if (nprot != VM_PROT_READ)
124		return (-1);
125	if (offset == 0) {
126		*paddr = vtophys(sc->info);
127		return (0);
128	}
129	i = (offset - sc->info->o_ring) / PAGE_SIZE;
130	if (i >= NRING)
131		return (-1);
132	*paddr = vtophys(sc->ring[i]);
133	return (0);
134}
135
136static void
137adlink_intr(void *arg)
138{
139	struct softc *sc;
140	uint32_t u;
141	int i;
142
143	sc = arg;
144	u = bus_space_read_4(sc->t0, sc->h0, 0x38);
145	if (!(u & 0x00800000))
146		return;
147	bus_space_write_4(sc->t0, sc->h0, 0x38, u | 0x003f4000);
148
149	sc->stat[sc->idx] = 1;
150	i = (++sc->idx) % NRING;
151	sc->idx = i;
152	bus_space_write_4(sc->t0, sc->h0, 0x24, sc->phys[i]);
153	bus_space_write_4(sc->t0, sc->h0, 0x28, PAGE_SIZE);
154}
155
156static struct cdevsw adlink_cdevsw = {
157	.d_open =	adlink_open,
158	.d_close =	nullclose,
159	.d_mmap =	adlink_mmap,
160	.d_name =	"adlink",
161};
162
163static devclass_t adlink_devclass;
164
165static int
166adlink_probe(device_t self)
167{
168
169	if (pci_get_devid(self) != 0x80da10e8)
170		return (ENXIO);
171	device_set_desc(self, "Adlink PCI-9812 4 ch 12 bit 20 msps");
172	return (0);
173}
174
175static int
176adlink_attach(device_t self)
177{
178	struct softc *sc;
179	int rid, i;
180
181	sc = device_get_softc(self);
182	bzero(sc, sizeof *sc);
183	sc->device = self;
184
185	rid = 0x10;
186	sc->r0 = bus_alloc_resource(self, SYS_RES_IOPORT, &rid,
187	    0, ~0, 1, RF_ACTIVE);
188	if (sc->r0 == NULL)
189		return(ENODEV);
190	sc->t0 = rman_get_bustag(sc->r0);
191	sc->h0 = rman_get_bushandle(sc->r0);
192	printf("Res0 %x %x\n", sc->t0, sc->h0);
193
194	rid = 0x14;
195	sc->r1 =  bus_alloc_resource(self, SYS_RES_IOPORT, &rid,
196            0, ~0, 1, RF_ACTIVE);
197	if (sc->r1 == NULL)
198		return(ENODEV);
199	sc->t1 = rman_get_bustag(sc->r1);
200	sc->h1 = rman_get_bushandle(sc->r1);
201	printf("Res1 %x %x\n", sc->t1, sc->h1);
202
203	rid = 0x0;
204	sc->ri =  bus_alloc_resource(self, SYS_RES_IRQ, &rid,
205            0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
206	if (sc->ri == NULL)
207		return (ENODEV);
208
209	i = bus_setup_intr(self, sc->ri, INTR_TYPE_MISC,
210	    adlink_intr, sc, &sc->intrhand);
211
212	if (i)
213		return (ENODEV);
214
215	sc->dev = make_dev(&adlink_cdevsw, device_get_unit(self),
216	    UID_ROOT, GID_WHEEL, 0444, "adlink%d", device_get_unit(self));
217	sc->dev->si_drv1 = sc;
218
219	return (0);
220}
221
222static device_method_t adlink_methods[] = {
223	/* Device interface */
224	DEVMETHOD(device_probe,		adlink_probe),
225	DEVMETHOD(device_attach,	adlink_attach),
226	DEVMETHOD(device_suspend,	bus_generic_suspend),
227	DEVMETHOD(device_resume,	bus_generic_resume),
228	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
229	{0, 0}
230};
231
232static driver_t adlink_driver = {
233	"adlink",
234	adlink_methods,
235	sizeof(struct softc)
236};
237
238DRIVER_MODULE(adlink, pci, adlink_driver, adlink_devclass, 0, 0);
239