FreeBSD/Linux Kernel Cross Reference
sys/dev/isa/satlink.c
1 /* $NetBSD: satlink.c,v 1.22 2003/05/09 23:51:29 fvdl Exp $ */
2
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
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
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 */
46
47 #include <sys/cdefs.h>
48 __KERNEL_RCSID(0, "$NetBSD: satlink.c,v 1.22 2003/05/09 23:51:29 fvdl Exp $");
49
50 #include <sys/param.h>
51 #include <sys/systm.h>
52 #include <sys/callout.h>
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 */
80 isa_chipset_tag_t sc_ic; /* ISA chipset info */
81 int sc_drq; /* the DRQ we're using */
82 bus_size_t sc_bufsize; /* DMA buffer size */
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 */
90 struct callout sc_ch; /* callout pseudo-interrupt */
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 */
101 #define SATLINK_TIMEOUT (hz/10)
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
107 CFATTACH_DECL(satlink, sizeof(struct satlink_softc),
108 satlinkprobe, satlinkattach, NULL, NULL);
109
110 extern struct cfdriver satlink_cd;
111
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 dev_type_kqfilter(satlinkkqfilter);
118
119 const struct cdevsw satlink_cdevsw = {
120 satlinkopen, satlinkclose, satlinkread, nowrite, satlinkioctl,
121 nostop, notty, satlinkpoll, nommap, satlinkkqfilter,
122 };
123
124 int
125 satlinkprobe(parent, match, aux)
126 struct device *parent;
127 struct cfdata *match;
128 void *aux;
129 {
130 struct isa_attach_args *ia = aux;
131 bus_space_tag_t iot = ia->ia_iot;
132 bus_space_handle_t ioh;
133 int rv = 0;
134
135 if (ia->ia_nio < 1)
136 return (0);
137 if (ia->ia_ndrq < 1)
138 return (0);
139
140 if (ISA_DIRECT_CONFIG(ia))
141 return (0);
142
143 /* Don't allow wildcarding of iobase or drq. */
144 if (ia->ia_io[0].ir_addr == ISACF_PORT_DEFAULT)
145 return (0);
146 if (ia->ia_drq[0].ir_drq == ISACF_DRQ_DEFAULT)
147 return (0);
148
149 if (bus_space_map(iot, ia->ia_io[0].ir_addr, SATLINK_IOSIZE, 0, &ioh))
150 return (0);
151
152 /*
153 * XXX Should check manufacturer ID here, or something.
154 */
155
156 rv = 1;
157
158 ia->ia_nio = 1;
159 ia->ia_io[0].ir_size = SATLINK_IOSIZE;
160
161 ia->ia_ndrq = 1;
162
163 ia->ia_nirq = 0;
164 ia->ia_niomem = 0;
165
166 bus_space_unmap(iot, ioh, SATLINK_IOSIZE);
167 return (rv);
168 }
169
170 void
171 satlinkattach(parent, self, aux)
172 struct device *parent, *self;
173 void *aux;
174 {
175 struct satlink_softc *sc = (struct satlink_softc *)self;
176 struct isa_attach_args *ia = aux;
177 bus_space_tag_t iot = ia->ia_iot;
178 bus_space_handle_t ioh;
179 bus_addr_t ringaddr;
180
181 printf("\n");
182
183 /* Map the card. */
184 if (bus_space_map(iot, ia->ia_io[0].ir_addr, SATLINK_IOSIZE, 0, &ioh)) {
185 printf("%s: can't map i/o space\n", sc->sc_dev.dv_xname);
186 return;
187 }
188
189 sc->sc_iot = iot;
190 sc->sc_ioh = ioh;
191 sc->sc_ic = ia->ia_ic;
192 sc->sc_drq = ia->ia_drq[0].ir_drq;
193
194 /* Reset the card. */
195 bus_space_write_1(iot, ioh, SATLINK_COMMAND, SATLINK_CMD_RESET);
196
197 /* Read ID from the card. */
198 sc->sc_id.sid_mfrid =
199 bus_space_read_1(iot, ioh, SATLINK_MFRID_L) |
200 (bus_space_read_1(iot, ioh, SATLINK_MFRID_H) << 8);
201 sc->sc_id.sid_grpid = bus_space_read_1(iot, ioh, SATLINK_GRPID);
202 sc->sc_id.sid_userid =
203 bus_space_read_1(iot, ioh, SATLINK_USERID_L) |
204 (bus_space_read_1(iot, ioh, SATLINK_USERID_H) << 8);
205 sc->sc_id.sid_serial =
206 bus_space_read_1(iot, ioh, SATLINK_SER_L) |
207 (bus_space_read_1(iot, ioh, SATLINK_SER_M0) << 8) |
208 (bus_space_read_1(iot, ioh, SATLINK_SER_M1) << 16) |
209 (bus_space_read_1(iot, ioh, SATLINK_SER_H) << 24);
210
211 printf("%s: mfrid 0x%x, grpid 0x%x, userid 0x%x, serial %d\n",
212 sc->sc_dev.dv_xname, sc->sc_id.sid_mfrid,
213 sc->sc_id.sid_grpid, sc->sc_id.sid_userid,
214 sc->sc_id.sid_serial);
215
216 callout_init(&sc->sc_ch);
217
218 sc->sc_bufsize = isa_dmamaxsize(sc->sc_ic, sc->sc_drq);
219
220 /* Allocate and map the ring buffer. */
221 if (isa_dmamem_alloc(sc->sc_ic, sc->sc_drq, sc->sc_bufsize,
222 &ringaddr, BUS_DMA_NOWAIT)) {
223 printf("%s: can't allocate ring buffer\n",
224 sc->sc_dev.dv_xname);
225 return;
226 }
227 if (isa_dmamem_map(sc->sc_ic, sc->sc_drq, ringaddr, sc->sc_bufsize,
228 &sc->sc_buf, BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) {
229 printf("%s: can't map ring buffer\n", sc->sc_dev.dv_xname);
230 isa_dmamem_free(sc->sc_ic, sc->sc_drq, ringaddr,
231 sc->sc_bufsize);
232 return;
233 }
234
235 if (isa_drq_alloc(sc->sc_ic, sc->sc_drq) != 0) {
236 printf("%s: can't reserve drq %d\n",
237 sc->sc_dev.dv_xname, sc->sc_drq);
238 isa_dmamem_unmap(sc->sc_ic, sc->sc_drq, sc->sc_buf,
239 sc->sc_bufsize);
240 isa_dmamem_free(sc->sc_ic, sc->sc_drq, ringaddr,
241 sc->sc_bufsize);
242 return;
243 }
244
245 /* Create the DMA map. */
246 if (isa_dmamap_create(sc->sc_ic, sc->sc_drq, sc->sc_bufsize,
247 BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW)) {
248 printf("%s: can't create DMA map\n", sc->sc_dev.dv_xname);
249 isa_dmamem_unmap(sc->sc_ic, sc->sc_drq, sc->sc_buf,
250 sc->sc_bufsize);
251 isa_dmamem_free(sc->sc_ic, sc->sc_drq, ringaddr,
252 sc->sc_bufsize);
253 return;
254 }
255 }
256
257 int
258 satlinkopen(dev, flags, fmt, p)
259 dev_t dev;
260 int flags, fmt;
261 struct proc *p;
262 {
263 struct satlink_softc *sc;
264 int error;
265
266 sc = device_lookup(&satlink_cd, minor(dev));
267 if (sc == NULL)
268 return (ENXIO);
269
270 if (sc->sc_flags & SATF_ISOPEN)
271 return (EBUSY);
272
273 bus_space_write_1(sc->sc_iot, sc->sc_ioh, SATLINK_COMMAND,
274 SATLINK_CMD_RESET);
275
276 /* Reset the ring buffer, and start the DMA loop. */
277 sc->sc_uptr = 0;
278 sc->sc_sptr = 0;
279 sc->sc_lastresid = sc->sc_bufsize;
280 memset(sc->sc_buf, 0, sc->sc_bufsize);
281 error = isa_dmastart(sc->sc_ic, sc->sc_drq, sc->sc_buf,
282 sc->sc_bufsize, NULL, DMAMODE_READ|DMAMODE_LOOP, BUS_DMA_WAITOK);
283 if (error)
284 return (error);
285
286 sc->sc_flags |= SATF_ISOPEN;
287
288 callout_reset(&sc->sc_ch, SATLINK_TIMEOUT, satlinktimeout, sc);
289
290 return (0);
291 }
292
293 int
294 satlinkclose(dev, flags, fmt, p)
295 dev_t dev;
296 int flags, fmt;
297 struct proc *p;
298 {
299 struct satlink_softc *sc = device_lookup(&satlink_cd, minor(dev));
300 int s;
301
302 s = splsoftclock();
303 sc->sc_flags &= ~SATF_ISOPEN;
304 splx(s);
305
306 isa_dmaabort(sc->sc_ic, sc->sc_drq);
307 callout_stop(&sc->sc_ch);
308
309 return (0);
310 }
311
312 int
313 satlinkread(dev, uio, flags)
314 dev_t dev;
315 struct uio *uio;
316 int flags;
317 {
318 struct satlink_softc *sc = device_lookup(&satlink_cd, minor(dev));
319 int error, s, count, sptr;
320 int wrapcnt, oresid;
321
322 s = splsoftclock();
323
324 /* Wait for data to be available. */
325 while (sc->sc_sptr == sc->sc_uptr) {
326 if (flags & O_NONBLOCK) {
327 splx(s);
328 return (EWOULDBLOCK);
329 }
330 sc->sc_flags |= SATF_DATA;
331 if ((error = tsleep(sc, TTIPRI | PCATCH, "satio", 0)) != 0) {
332 splx(s);
333 return (error);
334 }
335 }
336
337 sptr = sc->sc_sptr;
338 splx(s);
339
340 /* Compute number of readable bytes. */
341 if (sptr > sc->sc_uptr)
342 count = sptr - sc->sc_uptr;
343 else
344 count = sc->sc_bufsize - sc->sc_uptr + sptr;
345
346 if (count > uio->uio_resid)
347 count = uio->uio_resid;
348
349 /* Send data out to user. */
350 if (sptr > sc->sc_uptr) {
351 /*
352 * Easy case - no wrap-around.
353 */
354 error = uiomove(&sc->sc_buf[sc->sc_uptr], count, uio);
355 if (error == 0) {
356 sc->sc_uptr += count;
357 if (sc->sc_uptr == sc->sc_bufsize)
358 sc->sc_uptr = 0;
359 }
360 return (error);
361 }
362
363 /*
364 * We wrap around. Copy to the end of the ring...
365 */
366 wrapcnt = sc->sc_bufsize - sc->sc_uptr;
367 oresid = uio->uio_resid;
368 if (wrapcnt > uio->uio_resid)
369 wrapcnt = uio->uio_resid;
370 error = uiomove(&sc->sc_buf[sc->sc_uptr], wrapcnt, uio);
371 sc->sc_uptr = 0;
372 if (error != 0 || wrapcnt == oresid)
373 return (error);
374
375 /* ...and the rest. */
376 count -= wrapcnt;
377 error = uiomove(sc->sc_buf, count, uio);
378 sc->sc_uptr += count;
379 if (sc->sc_uptr == sc->sc_bufsize)
380 sc->sc_uptr = 0;
381
382 return (error);
383 }
384
385 int
386 satlinkioctl(dev, cmd, data, flags, p)
387 dev_t dev;
388 u_long cmd;
389 caddr_t data;
390 int flags;
391 struct proc *p;
392 {
393 struct satlink_softc *sc = device_lookup(&satlink_cd, minor(dev));
394
395 switch (cmd) {
396 case SATIORESET:
397 bus_space_write_1(sc->sc_iot, sc->sc_ioh, SATLINK_COMMAND,
398 SATLINK_CMD_RESET);
399 sc->sc_uptr = isa_dmacount(sc->sc_ic, sc->sc_drq);
400 sc->sc_sptr = sc->sc_uptr;
401 break;
402
403 case SATIOGID:
404 memcpy(data, &sc->sc_id, sizeof(sc->sc_id));
405 break;
406
407 default:
408 return (ENOTTY);
409 }
410
411 return (0);
412 }
413
414 int
415 satlinkpoll(dev, events, p)
416 dev_t dev;
417 int events;
418 struct proc *p;
419 {
420 struct satlink_softc *sc = device_lookup(&satlink_cd, minor(dev));
421 int s, revents;
422
423 revents = events & (POLLOUT | POLLWRNORM);
424
425 /* Attempt to save some work. */
426 if ((events & (POLLIN | POLLRDNORM)) == 0)
427 return (revents);
428
429 /* We're timeout-driven, so must block the clock. */
430 s = splsoftclock();
431 if (sc->sc_uptr != sc->sc_sptr)
432 revents |= events & (POLLIN | POLLRDNORM);
433 else
434 selrecord(p, &sc->sc_selq);
435 splx(s);
436
437 return (revents);
438 }
439
440 static void
441 filt_satlinkrdetach(struct knote *kn)
442 {
443 struct satlink_softc *sc = kn->kn_hook;
444 int s;
445
446 s = splsoftclock();
447 SLIST_REMOVE(&sc->sc_selq.sel_klist, kn, knote, kn_selnext);
448 splx(s);
449 }
450
451 static int
452 filt_satlinkread(struct knote *kn, long hint)
453 {
454 struct satlink_softc *sc = kn->kn_hook;
455
456 if (sc->sc_uptr == sc->sc_sptr)
457 return (0);
458
459 if (sc->sc_sptr > sc->sc_uptr)
460 kn->kn_data = sc->sc_sptr - sc->sc_uptr;
461 else
462 kn->kn_data = (sc->sc_bufsize - sc->sc_uptr) +
463 sc->sc_sptr;
464 return (1);
465 }
466
467 static const struct filterops satlinkread_filtops =
468 { 1, NULL, filt_satlinkrdetach, filt_satlinkread };
469
470 static const struct filterops satlink_seltrue_filtops =
471 { 1, NULL, filt_satlinkrdetach, filt_seltrue };
472
473 int
474 satlinkkqfilter(dev_t dev, struct knote *kn)
475 {
476 struct satlink_softc *sc = device_lookup(&satlink_cd, minor(dev));
477 struct klist *klist;
478 int s;
479
480 switch (kn->kn_filter) {
481 case EVFILT_READ:
482 klist = &sc->sc_selq.sel_klist;
483 kn->kn_fop = &satlinkread_filtops;
484 break;
485
486 case EVFILT_WRITE:
487 klist = &sc->sc_selq.sel_klist;
488 kn->kn_fop = &satlink_seltrue_filtops;
489 break;
490
491 default:
492 return (1);
493 }
494
495 kn->kn_hook = sc;
496
497 s = splsoftclock();
498 SLIST_INSERT_HEAD(klist, kn, kn_selnext);
499 splx(s);
500
501 return (0);
502 }
503
504 void
505 satlinktimeout(arg)
506 void *arg;
507 {
508 struct satlink_softc *sc = arg;
509 bus_size_t resid;
510 int newidx;
511
512 if ((sc->sc_flags & SATF_ISOPEN) == 0)
513 return;
514
515 /*
516 * Get the current residual count from the DMA controller
517 * and compute the satlink's index into the ring buffer.
518 */
519 resid = isa_dmacount(sc->sc_ic, sc->sc_drq);
520 newidx = sc->sc_bufsize - resid;
521 if (newidx == sc->sc_bufsize)
522 newidx = 0;
523
524 if (newidx == sc->sc_sptr)
525 goto out;
526
527 sc->sc_sptr = newidx;
528
529 /* Wake up anyone blocked in read... */
530 if (sc->sc_flags & SATF_DATA) {
531 sc->sc_flags &= ~SATF_DATA;
532 wakeup(sc);
533 }
534
535 /* Wake up anyone blocked in poll... */
536 selnotify(&sc->sc_selq, 0);
537
538 out:
539 callout_reset(&sc->sc_ch, SATLINK_TIMEOUT, satlinktimeout, sc);
540 }
Cache object: 4941861594aa044ade102e1772a314fe
|