Annotation of src/sys/dev/isa/satlink.c, Revision 1.11.2.6
1.11.2.5 nathanw 1: /* $NetBSD$ */
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.11.2.2 nathanw 46:
47: #include <sys/cdefs.h>
1.11.2.5 nathanw 48: __KERNEL_RCSID(0, "$NetBSD$");
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:
65: #include <machine/cpu.h>
66: #include <machine/bus.h>
67: #include <machine/intr.h>
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.1 hpeyerl 83: caddr_t sc_buf; /* ring buffer for incoming data */
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.9 thorpej 90: struct callout 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: /*
98: * Our pesudo-interrupt. Since up to 328 bytes can arrive in 1/100 of
99: * a second, this gives us 3280 bytes per timeout.
100: */
1.8 thorpej 101: #define SATLINK_TIMEOUT (hz/10)
1.1 hpeyerl 102:
103: int satlinkprobe __P((struct device *, struct cfdata *, void *));
104: void satlinkattach __P((struct device *, struct device *, void *));
105: void satlinktimeout __P((void *));
106:
1.11.2.6! nathanw 107: CFATTACH_DECL(satlink, sizeof(struct satlink_softc),
! 108: satlinkprobe, satlinkattach, NULL, NULL);
1.1 hpeyerl 109:
1.4 thorpej 110: extern struct cfdriver satlink_cd;
1.1 hpeyerl 111:
1.11.2.5 nathanw 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);
117:
118: const struct cdevsw satlink_cdevsw = {
119: satlinkopen, satlinkclose, satlinkread, nowrite, satlinkioctl,
120: nostop, notty, satlinkpoll, nommap,
121: };
1.1 hpeyerl 122:
123: int
124: satlinkprobe(parent, match, aux)
125: struct device *parent;
126: struct cfdata *match;
127: void *aux;
128: {
129: struct isa_attach_args *ia = aux;
130: bus_space_tag_t iot = ia->ia_iot;
131: bus_space_handle_t ioh;
132: int rv = 0;
133:
1.11.2.3 nathanw 134: if (ia->ia_nio < 1)
135: return (0);
136: if (ia->ia_ndrq < 1)
137: return (0);
138:
139: if (ISA_DIRECT_CONFIG(ia))
140: return (0);
141:
1.1 hpeyerl 142: /* Don't allow wildcarding of iobase or drq. */
1.11.2.3 nathanw 143: if (ia->ia_io[0].ir_addr == ISACF_PORT_DEFAULT)
1.1 hpeyerl 144: return (0);
1.11.2.3 nathanw 145: if (ia->ia_drq[0].ir_drq == ISACF_DRQ_DEFAULT)
1.1 hpeyerl 146: return (0);
147:
1.11.2.3 nathanw 148: if (bus_space_map(iot, ia->ia_io[0].ir_addr, SATLINK_IOSIZE, 0, &ioh))
1.1 hpeyerl 149: return (0);
150:
151: /*
152: * XXX Should check manufacturer ID here, or something.
153: */
154:
155: rv = 1;
1.11.2.3 nathanw 156:
157: ia->ia_nio = 1;
158: ia->ia_io[0].ir_size = SATLINK_IOSIZE;
159:
160: ia->ia_ndrq = 1;
161:
162: ia->ia_nirq = 0;
163: ia->ia_niomem = 0;
1.1 hpeyerl 164:
165: bus_space_unmap(iot, ioh, SATLINK_IOSIZE);
166: return (rv);
167: }
168:
169: void
170: satlinkattach(parent, self, aux)
171: struct device *parent, *self;
172: void *aux;
173: {
174: struct satlink_softc *sc = (struct satlink_softc *)self;
175: struct isa_attach_args *ia = aux;
176: bus_space_tag_t iot = ia->ia_iot;
177: bus_space_handle_t ioh;
178: bus_addr_t ringaddr;
179:
180: printf("\n");
181:
182: /* Map the card. */
1.11.2.3 nathanw 183: if (bus_space_map(iot, ia->ia_io[0].ir_addr, SATLINK_IOSIZE, 0, &ioh)) {
1.1 hpeyerl 184: printf("%s: can't map i/o space\n", sc->sc_dev.dv_xname);
185: return;
186: }
187:
188: sc->sc_iot = iot;
189: sc->sc_ioh = ioh;
1.6 thorpej 190: sc->sc_ic = ia->ia_ic;
1.11.2.3 nathanw 191: sc->sc_drq = ia->ia_drq[0].ir_drq;
1.1 hpeyerl 192:
193: /* Reset the card. */
194: bus_space_write_1(iot, ioh, SATLINK_COMMAND, SATLINK_CMD_RESET);
195:
196: /* Read ID from the card. */
197: sc->sc_id.sid_mfrid =
198: bus_space_read_1(iot, ioh, SATLINK_MFRID_L) |
199: (bus_space_read_1(iot, ioh, SATLINK_MFRID_H) << 8);
200: sc->sc_id.sid_grpid = bus_space_read_1(iot, ioh, SATLINK_GRPID);
201: sc->sc_id.sid_userid =
202: bus_space_read_1(iot, ioh, SATLINK_USERID_L) |
203: (bus_space_read_1(iot, ioh, SATLINK_USERID_H) << 8);
204: sc->sc_id.sid_serial =
205: bus_space_read_1(iot, ioh, SATLINK_SER_L) |
206: (bus_space_read_1(iot, ioh, SATLINK_SER_M0) << 8) |
207: (bus_space_read_1(iot, ioh, SATLINK_SER_M1) << 16) |
208: (bus_space_read_1(iot, ioh, SATLINK_SER_H) << 24);
209:
210: printf("%s: mfrid 0x%x, grpid 0x%x, userid 0x%x, serial %d\n",
211: sc->sc_dev.dv_xname, sc->sc_id.sid_mfrid,
212: sc->sc_id.sid_grpid, sc->sc_id.sid_userid,
213: sc->sc_id.sid_serial);
214:
1.10 thorpej 215: callout_init(&sc->sc_ch);
1.9 thorpej 216:
1.8 thorpej 217: sc->sc_bufsize = isa_dmamaxsize(sc->sc_ic, sc->sc_drq);
218:
1.1 hpeyerl 219: /* Allocate and map the ring buffer. */
1.8 thorpej 220: if (isa_dmamem_alloc(sc->sc_ic, sc->sc_drq, sc->sc_bufsize,
1.1 hpeyerl 221: &ringaddr, BUS_DMA_NOWAIT)) {
222: printf("%s: can't allocate ring buffer\n",
223: sc->sc_dev.dv_xname);
224: return;
225: }
1.8 thorpej 226: if (isa_dmamem_map(sc->sc_ic, sc->sc_drq, ringaddr, sc->sc_bufsize,
1.5 thorpej 227: &sc->sc_buf, BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) {
1.1 hpeyerl 228: printf("%s: can't map ring buffer\n", sc->sc_dev.dv_xname);
1.6 thorpej 229: isa_dmamem_free(sc->sc_ic, sc->sc_drq, ringaddr,
1.8 thorpej 230: sc->sc_bufsize);
1.1 hpeyerl 231: return;
232: }
233:
234: /* Create the DMA map. */
1.8 thorpej 235: if (isa_dmamap_create(sc->sc_ic, sc->sc_drq, sc->sc_bufsize,
1.1 hpeyerl 236: BUS_DMA_NOWAIT)) {
237: printf("%s: can't create DMA map\n", sc->sc_dev.dv_xname);
1.6 thorpej 238: isa_dmamem_unmap(sc->sc_ic, sc->sc_drq, sc->sc_buf,
1.8 thorpej 239: sc->sc_bufsize);
1.6 thorpej 240: isa_dmamem_free(sc->sc_ic, sc->sc_drq, ringaddr,
1.8 thorpej 241: sc->sc_bufsize);
1.1 hpeyerl 242: return;
243: }
244: }
245:
246: int
247: satlinkopen(dev, flags, fmt, p)
248: dev_t dev;
249: int flags, fmt;
250: struct proc *p;
251: {
252: struct satlink_softc *sc;
1.11 thorpej 253: int error;
1.1 hpeyerl 254:
1.11 thorpej 255: sc = device_lookup(&satlink_cd, minor(dev));
256: if (sc == NULL)
1.1 hpeyerl 257: return (ENXIO);
258:
259: if (sc->sc_flags & SATF_ISOPEN)
260: return (EBUSY);
261:
262: bus_space_write_1(sc->sc_iot, sc->sc_ioh, SATLINK_COMMAND,
263: SATLINK_CMD_RESET);
264:
265: /* Reset the ring buffer, and start the DMA loop. */
266: sc->sc_uptr = 0;
267: sc->sc_sptr = 0;
1.8 thorpej 268: sc->sc_lastresid = sc->sc_bufsize;
1.11.2.1 nathanw 269: memset(sc->sc_buf, 0, sc->sc_bufsize);
1.6 thorpej 270: error = isa_dmastart(sc->sc_ic, sc->sc_drq, sc->sc_buf,
1.8 thorpej 271: sc->sc_bufsize, NULL, DMAMODE_READ|DMAMODE_LOOP, BUS_DMA_WAITOK);
1.1 hpeyerl 272: if (error)
273: return (error);
274:
275: sc->sc_flags |= SATF_ISOPEN;
276:
1.9 thorpej 277: callout_reset(&sc->sc_ch, SATLINK_TIMEOUT, satlinktimeout, sc);
1.1 hpeyerl 278:
279: return (0);
280: }
281:
282: int
283: satlinkclose(dev, flags, fmt, p)
284: dev_t dev;
285: int flags, fmt;
286: struct proc *p;
287: {
1.11 thorpej 288: struct satlink_softc *sc = device_lookup(&satlink_cd, minor(dev));
1.1 hpeyerl 289: int s;
290:
291: s = splsoftclock();
292: sc->sc_flags &= ~SATF_ISOPEN;
293: splx(s);
294:
1.6 thorpej 295: isa_dmaabort(sc->sc_ic, sc->sc_drq);
1.9 thorpej 296: callout_stop(&sc->sc_ch);
1.1 hpeyerl 297:
298: return (0);
299: }
300:
301: int
302: satlinkread(dev, uio, flags)
303: dev_t dev;
304: struct uio *uio;
305: int flags;
306: {
1.11 thorpej 307: struct satlink_softc *sc = device_lookup(&satlink_cd, minor(dev));
1.1 hpeyerl 308: int error, s, count, sptr;
309: int wrapcnt, oresid;
310:
311: s = splsoftclock();
312:
313: /* Wait for data to be available. */
314: while (sc->sc_sptr == sc->sc_uptr) {
315: if (flags & O_NONBLOCK) {
316: splx(s);
317: return (EWOULDBLOCK);
318: }
319: sc->sc_flags |= SATF_DATA;
320: if ((error = tsleep(sc, TTIPRI | PCATCH, "satio", 0)) != 0) {
321: splx(s);
322: return (error);
323: }
324: }
325:
326: sptr = sc->sc_sptr;
327: splx(s);
328:
329: /* Compute number of readable bytes. */
330: if (sptr > sc->sc_uptr)
331: count = sptr - sc->sc_uptr;
332: else
1.8 thorpej 333: count = sc->sc_bufsize - sc->sc_uptr + sptr;
1.1 hpeyerl 334:
335: if (count > uio->uio_resid)
336: count = uio->uio_resid;
337:
338: /* Send data out to user. */
339: if (sptr > sc->sc_uptr) {
340: /*
341: * Easy case - no wrap-around.
342: */
343: error = uiomove(&sc->sc_buf[sc->sc_uptr], count, uio);
344: if (error == 0) {
345: sc->sc_uptr += count;
1.8 thorpej 346: if (sc->sc_uptr == sc->sc_bufsize)
1.1 hpeyerl 347: sc->sc_uptr = 0;
348: }
349: return (error);
350: }
351:
352: /*
353: * We wrap around. Copy to the end of the ring...
354: */
1.8 thorpej 355: wrapcnt = sc->sc_bufsize - sc->sc_uptr;
1.1 hpeyerl 356: oresid = uio->uio_resid;
357: if (wrapcnt > uio->uio_resid)
358: wrapcnt = uio->uio_resid;
359: error = uiomove(&sc->sc_buf[sc->sc_uptr], wrapcnt, uio);
360: sc->sc_uptr = 0;
361: if (error != 0 || wrapcnt == oresid)
362: return (error);
363:
364: /* ...and the rest. */
365: count -= wrapcnt;
366: error = uiomove(sc->sc_buf, count, uio);
367: sc->sc_uptr += count;
1.8 thorpej 368: if (sc->sc_uptr == sc->sc_bufsize)
1.1 hpeyerl 369: sc->sc_uptr = 0;
370:
371: return (error);
372: }
373:
374: int
375: satlinkioctl(dev, cmd, data, flags, p)
376: dev_t dev;
377: u_long cmd;
378: caddr_t data;
379: int flags;
380: struct proc *p;
381: {
1.11 thorpej 382: struct satlink_softc *sc = device_lookup(&satlink_cd, minor(dev));
1.1 hpeyerl 383:
384: switch (cmd) {
385: case SATIORESET:
386: bus_space_write_1(sc->sc_iot, sc->sc_ioh, SATLINK_COMMAND,
387: SATLINK_CMD_RESET);
1.6 thorpej 388: sc->sc_uptr = isa_dmacount(sc->sc_ic, sc->sc_drq);
1.1 hpeyerl 389: sc->sc_sptr = sc->sc_uptr;
390: break;
391:
392: case SATIOGID:
1.11.2.1 nathanw 393: memcpy(data, &sc->sc_id, sizeof(sc->sc_id));
1.1 hpeyerl 394: break;
395:
396: default:
397: return (ENOTTY);
398: }
399:
400: return (0);
401: }
402:
403: int
404: satlinkpoll(dev, events, p)
405: dev_t dev;
406: int events;
407: struct proc *p;
408: {
1.11 thorpej 409: struct satlink_softc *sc = device_lookup(&satlink_cd, minor(dev));
1.1 hpeyerl 410: int s, revents;
411:
412: revents = events & (POLLOUT | POLLWRNORM);
413:
414: /* Attempt to save some work. */
415: if ((events & (POLLIN | POLLRDNORM)) == 0)
416: return (revents);
417:
418: /* We're timeout-driven, so must block the clock. */
419: s = splsoftclock();
420: if (sc->sc_uptr != sc->sc_sptr)
421: revents |= events & (POLLIN | POLLRDNORM);
422: else
423: selrecord(p, &sc->sc_selq);
424: splx(s);
425:
426: return (revents);
427: }
428:
429: void
430: satlinktimeout(arg)
431: void *arg;
432: {
433: struct satlink_softc *sc = arg;
434: bus_size_t resid;
435: int newidx;
436:
437: if ((sc->sc_flags & SATF_ISOPEN) == 0)
438: return;
439:
440: /*
441: * Get the current residual count from the DMA controller
442: * and compute the satlink's index into the ring buffer.
443: */
1.6 thorpej 444: resid = isa_dmacount(sc->sc_ic, sc->sc_drq);
1.8 thorpej 445: newidx = sc->sc_bufsize - resid;
446: if (newidx == sc->sc_bufsize)
1.1 hpeyerl 447: newidx = 0;
448:
449: if (newidx == sc->sc_sptr)
450: goto out;
451:
452: sc->sc_sptr = newidx;
453:
454: /* Wake up anyone blocked in read... */
455: if (sc->sc_flags & SATF_DATA) {
456: sc->sc_flags &= ~SATF_DATA;
457: wakeup(sc);
458: }
459:
460: /* Wake up anyone blocked in poll... */
461: selwakeup(&sc->sc_selq);
462:
463: out:
1.9 thorpej 464: callout_reset(&sc->sc_ch, SATLINK_TIMEOUT, satlinktimeout, sc);
1.1 hpeyerl 465: }
CVSweb <webmaster@jp.NetBSD.org>