Annotation of src/sys/dev/isa/satlink.c, Revision 1.37
1.37 ! cegger 1: /* $NetBSD: satlink.c,v 1.36 2008/03/01 14:16:50 rmind Exp $ */
1.4 thorpej 2:
1.1 hpeyerl 3: /*-
4: * Copyright (c) 1997 The NetBSD Foundation, Inc.
5: * All rights reserved.
6: *
7: * This code is derived from software contributed to The NetBSD Foundation
8: * by Canada Connect Corp.
9: *
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.
18: * 3. All advertising materials mentioning features or use of this software
19: * must display the following acknowledgement:
20: * This product includes software developed by the NetBSD
21: * Foundation, Inc. and its contributors.
22: * 4. Neither the name of The NetBSD Foundation nor the names of its
23: * contributors may be used to endorse or promote products derived
24: * from this software without specific prior written permission.
25: *
26: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1.2 jtc 29: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
1.1 hpeyerl 31: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36: * POSSIBILITY OF SUCH DAMAGE.
37: */
38:
39: /*
40: * Device driver for SatLink interface.
41: *
42: * This thing is really simple. We essentially DMA into a ring buffer
43: * which the user then reads from, and provide an ioctl interface to
44: * reset the card, etc.
45: */
1.14 lukem 46:
47: #include <sys/cdefs.h>
1.37 ! cegger 48: __KERNEL_RCSID(0, "$NetBSD: satlink.c,v 1.36 2008/03/01 14:16:50 rmind Exp $");
1.1 hpeyerl 49:
50: #include <sys/param.h>
51: #include <sys/systm.h>
1.9 thorpej 52: #include <sys/callout.h>
1.1 hpeyerl 53: #include <sys/errno.h>
54: #include <sys/ioctl.h>
55: #include <sys/device.h>
56: #include <sys/conf.h>
57: #include <sys/proc.h>
58: #include <sys/uio.h>
59: #include <sys/select.h>
60: #include <sys/poll.h>
61: #include <sys/kernel.h>
62: #include <sys/file.h>
63: #include <sys/tty.h>
64:
1.34 ad 65: #include <sys/cpu.h>
66: #include <sys/bus.h>
67: #include <sys/intr.h>
1.1 hpeyerl 68:
69: #include <dev/isa/isareg.h>
70: #include <dev/isa/isavar.h>
71: #include <dev/isa/isadmavar.h>
72:
73: #include <dev/isa/satlinkreg.h>
74: #include <dev/isa/satlinkio.h>
75:
76: struct satlink_softc {
77: struct device sc_dev; /* device glue */
78: bus_space_tag_t sc_iot; /* space tag */
79: bus_space_handle_t sc_ioh; /* space handle */
1.6 thorpej 80: isa_chipset_tag_t sc_ic; /* ISA chipset info */
1.1 hpeyerl 81: int sc_drq; /* the DRQ we're using */
1.8 thorpej 82: bus_size_t sc_bufsize; /* DMA buffer size */
1.31 christos 83: void * sc_buf; /* ring buffer for incoming data */
1.1 hpeyerl 84: int sc_uptr; /* user index into ring buffer */
85: int sc_sptr; /* satlink index into ring buffer */
86: int sc_flags; /* misc. flags. */
87: int sc_lastresid; /* residual */
88: struct selinfo sc_selq; /* our select/poll queue */
89: struct satlink_id sc_id; /* ID cached at attach time */
1.32 ad 90: callout_t sc_ch; /* callout pseudo-interrupt */
1.1 hpeyerl 91: };
92:
93: /* sc_flags */
94: #define SATF_ISOPEN 0x01 /* device is open */
95: #define SATF_DATA 0x02 /* waiting for data */
96:
97: /*
1.33 tsutsui 98: * Our pseudo-interrupt. Since up to 328 bytes can arrive in 1/100 of
1.1 hpeyerl 99: * a second, this gives us 3280 bytes per timeout.
100: */
1.8 thorpej 101: #define SATLINK_TIMEOUT (hz/10)
1.1 hpeyerl 102:
1.24 perry 103: int satlinkprobe(struct device *, struct cfdata *, void *);
104: void satlinkattach(struct device *, struct device *, void *);
105: void satlinktimeout(void *);
1.1 hpeyerl 106:
1.18 thorpej 107: CFATTACH_DECL(satlink, sizeof(struct satlink_softc),
1.19 thorpej 108: satlinkprobe, satlinkattach, NULL, NULL);
1.1 hpeyerl 109:
1.4 thorpej 110: extern struct cfdriver satlink_cd;
1.1 hpeyerl 111:
1.16 gehenna 112: dev_type_open(satlinkopen);
113: dev_type_close(satlinkclose);
114: dev_type_read(satlinkread);
115: dev_type_ioctl(satlinkioctl);
116: dev_type_poll(satlinkpoll);
1.20 jdolecek 117: dev_type_kqfilter(satlinkkqfilter);
1.16 gehenna 118:
119: const struct cdevsw satlink_cdevsw = {
120: satlinkopen, satlinkclose, satlinkread, nowrite, satlinkioctl,
1.28 christos 121: nostop, notty, satlinkpoll, nommap, satlinkkqfilter, D_OTHER,
1.16 gehenna 122: };
1.1 hpeyerl 123:
124: int
1.30 christos 125: satlinkprobe(struct device *parent, struct cfdata *match,
1.29 christos 126: void *aux)
1.1 hpeyerl 127: {
128: struct isa_attach_args *ia = aux;
129: bus_space_tag_t iot = ia->ia_iot;
130: bus_space_handle_t ioh;
131: int rv = 0;
132:
1.15 thorpej 133: if (ia->ia_nio < 1)
134: return (0);
135: if (ia->ia_ndrq < 1)
136: return (0);
137:
138: if (ISA_DIRECT_CONFIG(ia))
139: return (0);
140:
1.1 hpeyerl 141: /* Don't allow wildcarding of iobase or drq. */
1.23 drochner 142: if (ia->ia_io[0].ir_addr == ISA_UNKNOWN_PORT)
1.1 hpeyerl 143: return (0);
1.23 drochner 144: if (ia->ia_drq[0].ir_drq == ISA_UNKNOWN_DRQ)
1.1 hpeyerl 145: return (0);
146:
1.15 thorpej 147: if (bus_space_map(iot, ia->ia_io[0].ir_addr, SATLINK_IOSIZE, 0, &ioh))
1.1 hpeyerl 148: return (0);
149:
150: /*
151: * XXX Should check manufacturer ID here, or something.
152: */
153:
154: rv = 1;
1.15 thorpej 155:
156: ia->ia_nio = 1;
157: ia->ia_io[0].ir_size = SATLINK_IOSIZE;
158:
159: ia->ia_ndrq = 1;
160:
161: ia->ia_nirq = 0;
162: ia->ia_niomem = 0;
1.1 hpeyerl 163:
164: bus_space_unmap(iot, ioh, SATLINK_IOSIZE);
165: return (rv);
166: }
167:
168: void
1.30 christos 169: satlinkattach(struct device *parent, struct device *self, void *aux)
1.1 hpeyerl 170: {
171: struct satlink_softc *sc = (struct satlink_softc *)self;
172: struct isa_attach_args *ia = aux;
173: bus_space_tag_t iot = ia->ia_iot;
174: bus_space_handle_t ioh;
175: bus_addr_t ringaddr;
176:
177: printf("\n");
178:
179: /* Map the card. */
1.15 thorpej 180: if (bus_space_map(iot, ia->ia_io[0].ir_addr, SATLINK_IOSIZE, 0, &ioh)) {
1.37 ! cegger 181: aprint_error_dev(&sc->sc_dev, "can't map i/o space\n");
1.1 hpeyerl 182: return;
183: }
184:
185: sc->sc_iot = iot;
186: sc->sc_ioh = ioh;
1.6 thorpej 187: sc->sc_ic = ia->ia_ic;
1.15 thorpej 188: sc->sc_drq = ia->ia_drq[0].ir_drq;
1.1 hpeyerl 189:
190: /* Reset the card. */
191: bus_space_write_1(iot, ioh, SATLINK_COMMAND, SATLINK_CMD_RESET);
192:
193: /* Read ID from the card. */
194: sc->sc_id.sid_mfrid =
195: bus_space_read_1(iot, ioh, SATLINK_MFRID_L) |
196: (bus_space_read_1(iot, ioh, SATLINK_MFRID_H) << 8);
197: sc->sc_id.sid_grpid = bus_space_read_1(iot, ioh, SATLINK_GRPID);
198: sc->sc_id.sid_userid =
199: bus_space_read_1(iot, ioh, SATLINK_USERID_L) |
200: (bus_space_read_1(iot, ioh, SATLINK_USERID_H) << 8);
201: sc->sc_id.sid_serial =
202: bus_space_read_1(iot, ioh, SATLINK_SER_L) |
203: (bus_space_read_1(iot, ioh, SATLINK_SER_M0) << 8) |
204: (bus_space_read_1(iot, ioh, SATLINK_SER_M1) << 16) |
205: (bus_space_read_1(iot, ioh, SATLINK_SER_H) << 24);
206:
207: printf("%s: mfrid 0x%x, grpid 0x%x, userid 0x%x, serial %d\n",
1.37 ! cegger 208: device_xname(&sc->sc_dev), sc->sc_id.sid_mfrid,
1.1 hpeyerl 209: sc->sc_id.sid_grpid, sc->sc_id.sid_userid,
210: sc->sc_id.sid_serial);
211:
1.32 ad 212: callout_init(&sc->sc_ch, 0);
1.36 rmind 213: selinit(&sc->sc_selq);
1.9 thorpej 214:
1.8 thorpej 215: sc->sc_bufsize = isa_dmamaxsize(sc->sc_ic, sc->sc_drq);
216:
1.1 hpeyerl 217: /* Allocate and map the ring buffer. */
1.8 thorpej 218: if (isa_dmamem_alloc(sc->sc_ic, sc->sc_drq, sc->sc_bufsize,
1.1 hpeyerl 219: &ringaddr, BUS_DMA_NOWAIT)) {
1.37 ! cegger 220: aprint_error_dev(&sc->sc_dev, "can't allocate ring buffer\n");
1.1 hpeyerl 221: return;
222: }
1.8 thorpej 223: if (isa_dmamem_map(sc->sc_ic, sc->sc_drq, ringaddr, sc->sc_bufsize,
1.5 thorpej 224: &sc->sc_buf, BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) {
1.37 ! cegger 225: aprint_error_dev(&sc->sc_dev, "can't map ring buffer\n");
1.6 thorpej 226: isa_dmamem_free(sc->sc_ic, sc->sc_drq, ringaddr,
1.8 thorpej 227: sc->sc_bufsize);
1.1 hpeyerl 228: return;
229: }
230:
1.22 fvdl 231: if (isa_drq_alloc(sc->sc_ic, sc->sc_drq) != 0) {
1.37 ! cegger 232: aprint_error_dev(&sc->sc_dev, "can't reserve drq %d\n",
! 233: sc->sc_drq);
1.22 fvdl 234: isa_dmamem_unmap(sc->sc_ic, sc->sc_drq, sc->sc_buf,
235: sc->sc_bufsize);
236: isa_dmamem_free(sc->sc_ic, sc->sc_drq, ringaddr,
237: sc->sc_bufsize);
238: return;
239: }
240:
1.1 hpeyerl 241: /* Create the DMA map. */
1.8 thorpej 242: if (isa_dmamap_create(sc->sc_ic, sc->sc_drq, sc->sc_bufsize,
1.22 fvdl 243: BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW)) {
1.37 ! cegger 244: aprint_error_dev(&sc->sc_dev, "can't create DMA map\n");
1.6 thorpej 245: isa_dmamem_unmap(sc->sc_ic, sc->sc_drq, sc->sc_buf,
1.8 thorpej 246: sc->sc_bufsize);
1.6 thorpej 247: isa_dmamem_free(sc->sc_ic, sc->sc_drq, ringaddr,
1.8 thorpej 248: sc->sc_bufsize);
1.1 hpeyerl 249: return;
250: }
251: }
252:
253: int
1.30 christos 254: satlinkopen(dev_t dev, int flags, int fmt,
255: struct lwp *l)
1.1 hpeyerl 256: {
257: struct satlink_softc *sc;
1.11 thorpej 258: int error;
1.1 hpeyerl 259:
1.11 thorpej 260: sc = device_lookup(&satlink_cd, minor(dev));
261: if (sc == NULL)
1.1 hpeyerl 262: return (ENXIO);
263:
264: if (sc->sc_flags & SATF_ISOPEN)
265: return (EBUSY);
266:
267: bus_space_write_1(sc->sc_iot, sc->sc_ioh, SATLINK_COMMAND,
268: SATLINK_CMD_RESET);
269:
270: /* Reset the ring buffer, and start the DMA loop. */
1.25 perry 271: sc->sc_uptr = 0;
272: sc->sc_sptr = 0;
1.8 thorpej 273: sc->sc_lastresid = sc->sc_bufsize;
1.12 thorpej 274: memset(sc->sc_buf, 0, sc->sc_bufsize);
1.6 thorpej 275: error = isa_dmastart(sc->sc_ic, sc->sc_drq, sc->sc_buf,
1.8 thorpej 276: sc->sc_bufsize, NULL, DMAMODE_READ|DMAMODE_LOOP, BUS_DMA_WAITOK);
1.1 hpeyerl 277: if (error)
278: return (error);
279:
280: sc->sc_flags |= SATF_ISOPEN;
281:
1.9 thorpej 282: callout_reset(&sc->sc_ch, SATLINK_TIMEOUT, satlinktimeout, sc);
1.1 hpeyerl 283:
284: return (0);
285: }
286:
287: int
1.30 christos 288: satlinkclose(dev_t dev, int flags, int fmt,
289: struct lwp *l)
1.1 hpeyerl 290: {
1.11 thorpej 291: struct satlink_softc *sc = device_lookup(&satlink_cd, minor(dev));
1.1 hpeyerl 292: int s;
293:
294: s = splsoftclock();
295: sc->sc_flags &= ~SATF_ISOPEN;
296: splx(s);
297:
1.6 thorpej 298: isa_dmaabort(sc->sc_ic, sc->sc_drq);
1.9 thorpej 299: callout_stop(&sc->sc_ch);
1.1 hpeyerl 300:
301: return (0);
302: }
303:
304: int
305: satlinkread(dev, uio, flags)
306: dev_t dev;
307: struct uio *uio;
308: int flags;
309: {
1.11 thorpej 310: struct satlink_softc *sc = device_lookup(&satlink_cd, minor(dev));
1.1 hpeyerl 311: int error, s, count, sptr;
312: int wrapcnt, oresid;
313:
314: s = splsoftclock();
315:
316: /* Wait for data to be available. */
317: while (sc->sc_sptr == sc->sc_uptr) {
318: if (flags & O_NONBLOCK) {
319: splx(s);
320: return (EWOULDBLOCK);
321: }
322: sc->sc_flags |= SATF_DATA;
323: if ((error = tsleep(sc, TTIPRI | PCATCH, "satio", 0)) != 0) {
324: splx(s);
325: return (error);
326: }
327: }
328:
329: sptr = sc->sc_sptr;
330: splx(s);
331:
332: /* Compute number of readable bytes. */
333: if (sptr > sc->sc_uptr)
334: count = sptr - sc->sc_uptr;
335: else
1.8 thorpej 336: count = sc->sc_bufsize - sc->sc_uptr + sptr;
1.1 hpeyerl 337:
338: if (count > uio->uio_resid)
339: count = uio->uio_resid;
340:
341: /* Send data out to user. */
342: if (sptr > sc->sc_uptr) {
343: /*
344: * Easy case - no wrap-around.
345: */
1.31 christos 346: error = uiomove((char *)sc->sc_buf + sc->sc_uptr, count, uio);
1.1 hpeyerl 347: if (error == 0) {
348: sc->sc_uptr += count;
1.8 thorpej 349: if (sc->sc_uptr == sc->sc_bufsize)
1.1 hpeyerl 350: sc->sc_uptr = 0;
351: }
352: return (error);
353: }
354:
355: /*
356: * We wrap around. Copy to the end of the ring...
357: */
1.8 thorpej 358: wrapcnt = sc->sc_bufsize - sc->sc_uptr;
1.1 hpeyerl 359: oresid = uio->uio_resid;
360: if (wrapcnt > uio->uio_resid)
361: wrapcnt = uio->uio_resid;
1.31 christos 362: error = uiomove((char *)sc->sc_buf + sc->sc_uptr, wrapcnt, uio);
1.1 hpeyerl 363: sc->sc_uptr = 0;
364: if (error != 0 || wrapcnt == oresid)
365: return (error);
366:
367: /* ...and the rest. */
368: count -= wrapcnt;
369: error = uiomove(sc->sc_buf, count, uio);
370: sc->sc_uptr += count;
1.8 thorpej 371: if (sc->sc_uptr == sc->sc_bufsize)
1.1 hpeyerl 372: sc->sc_uptr = 0;
373:
374: return (error);
375: }
376:
377: int
1.31 christos 378: satlinkioctl(dev_t dev, u_long cmd, void *data, int flags,
1.30 christos 379: struct lwp *l)
1.1 hpeyerl 380: {
1.11 thorpej 381: struct satlink_softc *sc = device_lookup(&satlink_cd, minor(dev));
1.1 hpeyerl 382:
383: switch (cmd) {
384: case SATIORESET:
385: bus_space_write_1(sc->sc_iot, sc->sc_ioh, SATLINK_COMMAND,
386: SATLINK_CMD_RESET);
1.6 thorpej 387: sc->sc_uptr = isa_dmacount(sc->sc_ic, sc->sc_drq);
1.1 hpeyerl 388: sc->sc_sptr = sc->sc_uptr;
389: break;
390:
391: case SATIOGID:
1.13 thorpej 392: memcpy(data, &sc->sc_id, sizeof(sc->sc_id));
1.1 hpeyerl 393: break;
394:
395: default:
396: return (ENOTTY);
397: }
398:
399: return (0);
400: }
401:
402: int
1.27 christos 403: satlinkpoll(dev, events, l)
1.1 hpeyerl 404: dev_t dev;
405: int events;
1.27 christos 406: struct lwp *l;
1.1 hpeyerl 407: {
1.11 thorpej 408: struct satlink_softc *sc = device_lookup(&satlink_cd, minor(dev));
1.1 hpeyerl 409: int s, revents;
410:
411: revents = events & (POLLOUT | POLLWRNORM);
412:
413: /* Attempt to save some work. */
414: if ((events & (POLLIN | POLLRDNORM)) == 0)
415: return (revents);
416:
417: /* We're timeout-driven, so must block the clock. */
418: s = splsoftclock();
419: if (sc->sc_uptr != sc->sc_sptr)
420: revents |= events & (POLLIN | POLLRDNORM);
421: else
1.27 christos 422: selrecord(l, &sc->sc_selq);
1.1 hpeyerl 423: splx(s);
424:
425: return (revents);
426: }
427:
1.20 jdolecek 428: static void
429: filt_satlinkrdetach(struct knote *kn)
430: {
431: struct satlink_softc *sc = kn->kn_hook;
432: int s;
433:
434: s = splsoftclock();
1.21 christos 435: SLIST_REMOVE(&sc->sc_selq.sel_klist, kn, knote, kn_selnext);
1.20 jdolecek 436: splx(s);
437: }
438:
439: static int
1.30 christos 440: filt_satlinkread(struct knote *kn, long hint)
1.20 jdolecek 441: {
442: struct satlink_softc *sc = kn->kn_hook;
443:
444: if (sc->sc_uptr == sc->sc_sptr)
445: return (0);
446:
447: if (sc->sc_sptr > sc->sc_uptr)
448: kn->kn_data = sc->sc_sptr - sc->sc_uptr;
449: else
450: kn->kn_data = (sc->sc_bufsize - sc->sc_uptr) +
451: sc->sc_sptr;
452: return (1);
453: }
454:
455: static const struct filterops satlinkread_filtops =
456: { 1, NULL, filt_satlinkrdetach, filt_satlinkread };
457:
458: static const struct filterops satlink_seltrue_filtops =
459: { 1, NULL, filt_satlinkrdetach, filt_seltrue };
460:
461: int
462: satlinkkqfilter(dev_t dev, struct knote *kn)
463: {
464: struct satlink_softc *sc = device_lookup(&satlink_cd, minor(dev));
465: struct klist *klist;
466: int s;
467:
468: switch (kn->kn_filter) {
469: case EVFILT_READ:
1.21 christos 470: klist = &sc->sc_selq.sel_klist;
1.20 jdolecek 471: kn->kn_fop = &satlinkread_filtops;
472: break;
473:
474: case EVFILT_WRITE:
1.21 christos 475: klist = &sc->sc_selq.sel_klist;
1.20 jdolecek 476: kn->kn_fop = &satlink_seltrue_filtops;
477: break;
478:
479: default:
1.35 pooka 480: return (EINVAL);
1.20 jdolecek 481: }
482:
483: kn->kn_hook = sc;
484:
485: s = splsoftclock();
486: SLIST_INSERT_HEAD(klist, kn, kn_selnext);
487: splx(s);
488:
489: return (0);
490: }
491:
1.1 hpeyerl 492: void
493: satlinktimeout(arg)
494: void *arg;
495: {
496: struct satlink_softc *sc = arg;
497: bus_size_t resid;
498: int newidx;
499:
500: if ((sc->sc_flags & SATF_ISOPEN) == 0)
501: return;
502:
503: /*
504: * Get the current residual count from the DMA controller
505: * and compute the satlink's index into the ring buffer.
506: */
1.6 thorpej 507: resid = isa_dmacount(sc->sc_ic, sc->sc_drq);
1.8 thorpej 508: newidx = sc->sc_bufsize - resid;
509: if (newidx == sc->sc_bufsize)
1.1 hpeyerl 510: newidx = 0;
511:
512: if (newidx == sc->sc_sptr)
513: goto out;
514:
515: sc->sc_sptr = newidx;
516:
517: /* Wake up anyone blocked in read... */
518: if (sc->sc_flags & SATF_DATA) {
519: sc->sc_flags &= ~SATF_DATA;
520: wakeup(sc);
521: }
522:
523: /* Wake up anyone blocked in poll... */
1.36 rmind 524: selnotify(&sc->sc_selq, 0, 0);
1.1 hpeyerl 525:
526: out:
1.9 thorpej 527: callout_reset(&sc->sc_ch, SATLINK_TIMEOUT, satlinktimeout, sc);
1.1 hpeyerl 528: }
CVSweb <webmaster@jp.NetBSD.org>