No empty .Rs/.Re
[netbsd-mini2440.git] / sys / dev / isa / satlink.c
blobb38f41e8dac76852b5b16810452bf2c8b2c56acb
1 /* $NetBSD: satlink.c,v 1.41 2009/05/12 08:44:19 cegger Exp $ */
3 /*-
4 * Copyright (c) 1997 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Canada Connect Corp.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * Device driver for SatLink interface.
35 * This thing is really simple. We essentially DMA into a ring buffer
36 * which the user then reads from, and provide an ioctl interface to
37 * reset the card, etc.
40 #include <sys/cdefs.h>
41 __KERNEL_RCSID(0, "$NetBSD: satlink.c,v 1.41 2009/05/12 08:44:19 cegger Exp $");
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/callout.h>
46 #include <sys/errno.h>
47 #include <sys/ioctl.h>
48 #include <sys/device.h>
49 #include <sys/conf.h>
50 #include <sys/proc.h>
51 #include <sys/uio.h>
52 #include <sys/select.h>
53 #include <sys/poll.h>
54 #include <sys/kernel.h>
55 #include <sys/file.h>
56 #include <sys/tty.h>
58 #include <sys/cpu.h>
59 #include <sys/bus.h>
60 #include <sys/intr.h>
62 #include <dev/isa/isareg.h>
63 #include <dev/isa/isavar.h>
64 #include <dev/isa/isadmavar.h>
66 #include <dev/isa/satlinkreg.h>
67 #include <dev/isa/satlinkio.h>
69 struct satlink_softc {
70 struct device sc_dev; /* device glue */
71 bus_space_tag_t sc_iot; /* space tag */
72 bus_space_handle_t sc_ioh; /* space handle */
73 isa_chipset_tag_t sc_ic; /* ISA chipset info */
74 int sc_drq; /* the DRQ we're using */
75 bus_size_t sc_bufsize; /* DMA buffer size */
76 void * sc_buf; /* ring buffer for incoming data */
77 int sc_uptr; /* user index into ring buffer */
78 int sc_sptr; /* satlink index into ring buffer */
79 int sc_flags; /* misc. flags. */
80 int sc_lastresid; /* residual */
81 struct selinfo sc_selq; /* our select/poll queue */
82 struct satlink_id sc_id; /* ID cached at attach time */
83 callout_t sc_ch; /* callout pseudo-interrupt */
86 /* sc_flags */
87 #define SATF_ISOPEN 0x01 /* device is open */
88 #define SATF_DATA 0x02 /* waiting for data */
91 * Our pseudo-interrupt. Since up to 328 bytes can arrive in 1/100 of
92 * a second, this gives us 3280 bytes per timeout.
94 #define SATLINK_TIMEOUT (hz/10)
96 int satlinkprobe(device_t, cfdata_t, void *);
97 void satlinkattach(device_t, device_t, void *);
98 void satlinktimeout(void *);
100 CFATTACH_DECL(satlink, sizeof(struct satlink_softc),
101 satlinkprobe, satlinkattach, NULL, NULL);
103 extern struct cfdriver satlink_cd;
105 dev_type_open(satlinkopen);
106 dev_type_close(satlinkclose);
107 dev_type_read(satlinkread);
108 dev_type_ioctl(satlinkioctl);
109 dev_type_poll(satlinkpoll);
110 dev_type_kqfilter(satlinkkqfilter);
112 const struct cdevsw satlink_cdevsw = {
113 satlinkopen, satlinkclose, satlinkread, nowrite, satlinkioctl,
114 nostop, notty, satlinkpoll, nommap, satlinkkqfilter, D_OTHER,
118 satlinkprobe(device_t parent, cfdata_t match, void *aux)
120 struct isa_attach_args *ia = aux;
121 bus_space_tag_t iot = ia->ia_iot;
122 bus_space_handle_t ioh;
123 int rv = 0;
125 if (ia->ia_nio < 1)
126 return (0);
127 if (ia->ia_ndrq < 1)
128 return (0);
130 if (ISA_DIRECT_CONFIG(ia))
131 return (0);
133 /* Don't allow wildcarding of iobase or drq. */
134 if (ia->ia_io[0].ir_addr == ISA_UNKNOWN_PORT)
135 return (0);
136 if (ia->ia_drq[0].ir_drq == ISA_UNKNOWN_DRQ)
137 return (0);
139 if (bus_space_map(iot, ia->ia_io[0].ir_addr, SATLINK_IOSIZE, 0, &ioh))
140 return (0);
143 * XXX Should check manufacturer ID here, or something.
146 rv = 1;
148 ia->ia_nio = 1;
149 ia->ia_io[0].ir_size = SATLINK_IOSIZE;
151 ia->ia_ndrq = 1;
153 ia->ia_nirq = 0;
154 ia->ia_niomem = 0;
156 bus_space_unmap(iot, ioh, SATLINK_IOSIZE);
157 return (rv);
160 void
161 satlinkattach(device_t parent, device_t self, void *aux)
163 struct satlink_softc *sc = (struct satlink_softc *)self;
164 struct isa_attach_args *ia = aux;
165 bus_space_tag_t iot = ia->ia_iot;
166 bus_space_handle_t ioh;
167 bus_addr_t ringaddr;
169 printf("\n");
171 /* Map the card. */
172 if (bus_space_map(iot, ia->ia_io[0].ir_addr, SATLINK_IOSIZE, 0, &ioh)) {
173 aprint_error_dev(&sc->sc_dev, "can't map i/o space\n");
174 return;
177 sc->sc_iot = iot;
178 sc->sc_ioh = ioh;
179 sc->sc_ic = ia->ia_ic;
180 sc->sc_drq = ia->ia_drq[0].ir_drq;
182 /* Reset the card. */
183 bus_space_write_1(iot, ioh, SATLINK_COMMAND, SATLINK_CMD_RESET);
185 /* Read ID from the card. */
186 sc->sc_id.sid_mfrid =
187 bus_space_read_1(iot, ioh, SATLINK_MFRID_L) |
188 (bus_space_read_1(iot, ioh, SATLINK_MFRID_H) << 8);
189 sc->sc_id.sid_grpid = bus_space_read_1(iot, ioh, SATLINK_GRPID);
190 sc->sc_id.sid_userid =
191 bus_space_read_1(iot, ioh, SATLINK_USERID_L) |
192 (bus_space_read_1(iot, ioh, SATLINK_USERID_H) << 8);
193 sc->sc_id.sid_serial =
194 bus_space_read_1(iot, ioh, SATLINK_SER_L) |
195 (bus_space_read_1(iot, ioh, SATLINK_SER_M0) << 8) |
196 (bus_space_read_1(iot, ioh, SATLINK_SER_M1) << 16) |
197 (bus_space_read_1(iot, ioh, SATLINK_SER_H) << 24);
199 printf("%s: mfrid 0x%x, grpid 0x%x, userid 0x%x, serial %d\n",
200 device_xname(&sc->sc_dev), sc->sc_id.sid_mfrid,
201 sc->sc_id.sid_grpid, sc->sc_id.sid_userid,
202 sc->sc_id.sid_serial);
204 callout_init(&sc->sc_ch, 0);
205 selinit(&sc->sc_selq);
207 sc->sc_bufsize = isa_dmamaxsize(sc->sc_ic, sc->sc_drq);
209 /* Allocate and map the ring buffer. */
210 if (isa_dmamem_alloc(sc->sc_ic, sc->sc_drq, sc->sc_bufsize,
211 &ringaddr, BUS_DMA_NOWAIT)) {
212 aprint_error_dev(&sc->sc_dev, "can't allocate ring buffer\n");
213 return;
215 if (isa_dmamem_map(sc->sc_ic, sc->sc_drq, ringaddr, sc->sc_bufsize,
216 &sc->sc_buf, BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) {
217 aprint_error_dev(&sc->sc_dev, "can't map ring buffer\n");
218 isa_dmamem_free(sc->sc_ic, sc->sc_drq, ringaddr,
219 sc->sc_bufsize);
220 return;
223 if (isa_drq_alloc(sc->sc_ic, sc->sc_drq) != 0) {
224 aprint_error_dev(&sc->sc_dev, "can't reserve drq %d\n",
225 sc->sc_drq);
226 isa_dmamem_unmap(sc->sc_ic, sc->sc_drq, sc->sc_buf,
227 sc->sc_bufsize);
228 isa_dmamem_free(sc->sc_ic, sc->sc_drq, ringaddr,
229 sc->sc_bufsize);
230 return;
233 /* Create the DMA map. */
234 if (isa_dmamap_create(sc->sc_ic, sc->sc_drq, sc->sc_bufsize,
235 BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW)) {
236 aprint_error_dev(&sc->sc_dev, "can't create DMA map\n");
237 isa_dmamem_unmap(sc->sc_ic, sc->sc_drq, sc->sc_buf,
238 sc->sc_bufsize);
239 isa_dmamem_free(sc->sc_ic, sc->sc_drq, ringaddr,
240 sc->sc_bufsize);
241 return;
246 satlinkopen(dev_t dev, int flags, int fmt,
247 struct lwp *l)
249 struct satlink_softc *sc;
250 int error;
252 sc = device_lookup_private(&satlink_cd, minor(dev));
254 if (sc == NULL)
255 return (ENXIO);
257 if (sc->sc_flags & SATF_ISOPEN)
258 return (EBUSY);
260 bus_space_write_1(sc->sc_iot, sc->sc_ioh, SATLINK_COMMAND,
261 SATLINK_CMD_RESET);
263 /* Reset the ring buffer, and start the DMA loop. */
264 sc->sc_uptr = 0;
265 sc->sc_sptr = 0;
266 sc->sc_lastresid = sc->sc_bufsize;
267 memset(sc->sc_buf, 0, sc->sc_bufsize);
268 error = isa_dmastart(sc->sc_ic, sc->sc_drq, sc->sc_buf,
269 sc->sc_bufsize, NULL, DMAMODE_READ|DMAMODE_LOOP, BUS_DMA_WAITOK);
270 if (error)
271 return (error);
273 sc->sc_flags |= SATF_ISOPEN;
275 callout_reset(&sc->sc_ch, SATLINK_TIMEOUT, satlinktimeout, sc);
277 return (0);
281 satlinkclose(dev_t dev, int flags, int fmt,
282 struct lwp *l)
284 struct satlink_softc *sc;
285 int s;
287 sc = device_lookup_private(&satlink_cd, minor(dev));
289 s = splsoftclock();
290 sc->sc_flags &= ~SATF_ISOPEN;
291 splx(s);
293 isa_dmaabort(sc->sc_ic, sc->sc_drq);
294 callout_stop(&sc->sc_ch);
296 return (0);
300 satlinkread(dev_t dev, struct uio *uio, int flags)
302 struct satlink_softc *sc;
303 int error, s, count, sptr;
304 int wrapcnt, oresid;
306 sc = device_lookup_private(&satlink_cd, minor(dev));
308 s = splsoftclock();
310 /* Wait for data to be available. */
311 while (sc->sc_sptr == sc->sc_uptr) {
312 if (flags & O_NONBLOCK) {
313 splx(s);
314 return (EWOULDBLOCK);
316 sc->sc_flags |= SATF_DATA;
317 if ((error = tsleep(sc, TTIPRI | PCATCH, "satio", 0)) != 0) {
318 splx(s);
319 return (error);
323 sptr = sc->sc_sptr;
324 splx(s);
326 /* Compute number of readable bytes. */
327 if (sptr > sc->sc_uptr)
328 count = sptr - sc->sc_uptr;
329 else
330 count = sc->sc_bufsize - sc->sc_uptr + sptr;
332 if (count > uio->uio_resid)
333 count = uio->uio_resid;
335 /* Send data out to user. */
336 if (sptr > sc->sc_uptr) {
338 * Easy case - no wrap-around.
340 error = uiomove((char *)sc->sc_buf + sc->sc_uptr, count, uio);
341 if (error == 0) {
342 sc->sc_uptr += count;
343 if (sc->sc_uptr == sc->sc_bufsize)
344 sc->sc_uptr = 0;
346 return (error);
350 * We wrap around. Copy to the end of the ring...
352 wrapcnt = sc->sc_bufsize - sc->sc_uptr;
353 oresid = uio->uio_resid;
354 if (wrapcnt > uio->uio_resid)
355 wrapcnt = uio->uio_resid;
356 error = uiomove((char *)sc->sc_buf + sc->sc_uptr, wrapcnt, uio);
357 sc->sc_uptr = 0;
358 if (error != 0 || wrapcnt == oresid)
359 return (error);
361 /* ...and the rest. */
362 count -= wrapcnt;
363 error = uiomove(sc->sc_buf, count, uio);
364 sc->sc_uptr += count;
365 if (sc->sc_uptr == sc->sc_bufsize)
366 sc->sc_uptr = 0;
368 return (error);
372 satlinkioctl(dev_t dev, u_long cmd, void *data, int flags,
373 struct lwp *l)
375 struct satlink_softc *sc;
377 sc = device_lookup_private(&satlink_cd, minor(dev));
379 switch (cmd) {
380 case SATIORESET:
381 bus_space_write_1(sc->sc_iot, sc->sc_ioh, SATLINK_COMMAND,
382 SATLINK_CMD_RESET);
383 sc->sc_uptr = isa_dmacount(sc->sc_ic, sc->sc_drq);
384 sc->sc_sptr = sc->sc_uptr;
385 break;
387 case SATIOGID:
388 memcpy(data, &sc->sc_id, sizeof(sc->sc_id));
389 break;
391 default:
392 return (ENOTTY);
395 return (0);
399 satlinkpoll(dev_t dev, int events, struct lwp *l)
401 struct satlink_softc *sc;
402 int s, revents;
404 sc = device_lookup_private(&satlink_cd, minor(dev));
406 revents = events & (POLLOUT | POLLWRNORM);
408 /* Attempt to save some work. */
409 if ((events & (POLLIN | POLLRDNORM)) == 0)
410 return (revents);
412 /* We're timeout-driven, so must block the clock. */
413 s = splsoftclock();
414 if (sc->sc_uptr != sc->sc_sptr)
415 revents |= events & (POLLIN | POLLRDNORM);
416 else
417 selrecord(l, &sc->sc_selq);
418 splx(s);
420 return (revents);
423 static void
424 filt_satlinkrdetach(struct knote *kn)
426 struct satlink_softc *sc = kn->kn_hook;
427 int s;
429 s = splsoftclock();
430 SLIST_REMOVE(&sc->sc_selq.sel_klist, kn, knote, kn_selnext);
431 splx(s);
434 static int
435 filt_satlinkread(struct knote *kn, long hint)
437 struct satlink_softc *sc = kn->kn_hook;
439 if (sc->sc_uptr == sc->sc_sptr)
440 return (0);
442 if (sc->sc_sptr > sc->sc_uptr)
443 kn->kn_data = sc->sc_sptr - sc->sc_uptr;
444 else
445 kn->kn_data = (sc->sc_bufsize - sc->sc_uptr) +
446 sc->sc_sptr;
447 return (1);
450 static const struct filterops satlinkread_filtops =
451 { 1, NULL, filt_satlinkrdetach, filt_satlinkread };
453 static const struct filterops satlink_seltrue_filtops =
454 { 1, NULL, filt_satlinkrdetach, filt_seltrue };
457 satlinkkqfilter(dev_t dev, struct knote *kn)
459 struct satlink_softc *sc;
460 struct klist *klist;
461 int s;
463 sc = device_lookup_private(&satlink_cd, minor(dev));
465 switch (kn->kn_filter) {
466 case EVFILT_READ:
467 klist = &sc->sc_selq.sel_klist;
468 kn->kn_fop = &satlinkread_filtops;
469 break;
471 case EVFILT_WRITE:
472 klist = &sc->sc_selq.sel_klist;
473 kn->kn_fop = &satlink_seltrue_filtops;
474 break;
476 default:
477 return (EINVAL);
480 kn->kn_hook = sc;
482 s = splsoftclock();
483 SLIST_INSERT_HEAD(klist, kn, kn_selnext);
484 splx(s);
486 return (0);
489 void
490 satlinktimeout(void *arg)
492 struct satlink_softc *sc = arg;
493 bus_size_t resid;
494 int newidx;
496 if ((sc->sc_flags & SATF_ISOPEN) == 0)
497 return;
500 * Get the current residual count from the DMA controller
501 * and compute the satlink's index into the ring buffer.
503 resid = isa_dmacount(sc->sc_ic, sc->sc_drq);
504 newidx = sc->sc_bufsize - resid;
505 if (newidx == sc->sc_bufsize)
506 newidx = 0;
508 if (newidx == sc->sc_sptr)
509 goto out;
511 sc->sc_sptr = newidx;
513 /* Wake up anyone blocked in read... */
514 if (sc->sc_flags & SATF_DATA) {
515 sc->sc_flags &= ~SATF_DATA;
516 wakeup(sc);
519 /* Wake up anyone blocked in poll... */
520 selnotify(&sc->sc_selq, 0, 0);
522 out:
523 callout_reset(&sc->sc_ch, SATLINK_TIMEOUT, satlinktimeout, sc);