1 /* $NetBSD: satlink.c,v 1.41 2009/05/12 08:44:19 cegger Exp $ */
4 * Copyright (c) 1997 The NetBSD Foundation, Inc.
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
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>
52 #include <sys/select.h>
54 #include <sys/kernel.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 */
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
;
130 if (ISA_DIRECT_CONFIG(ia
))
133 /* Don't allow wildcarding of iobase or drq. */
134 if (ia
->ia_io
[0].ir_addr
== ISA_UNKNOWN_PORT
)
136 if (ia
->ia_drq
[0].ir_drq
== ISA_UNKNOWN_DRQ
)
139 if (bus_space_map(iot
, ia
->ia_io
[0].ir_addr
, SATLINK_IOSIZE
, 0, &ioh
))
143 * XXX Should check manufacturer ID here, or something.
149 ia
->ia_io
[0].ir_size
= SATLINK_IOSIZE
;
156 bus_space_unmap(iot
, ioh
, SATLINK_IOSIZE
);
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
;
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");
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");
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
,
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",
226 isa_dmamem_unmap(sc
->sc_ic
, sc
->sc_drq
, sc
->sc_buf
,
228 isa_dmamem_free(sc
->sc_ic
, sc
->sc_drq
, ringaddr
,
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
,
239 isa_dmamem_free(sc
->sc_ic
, sc
->sc_drq
, ringaddr
,
246 satlinkopen(dev_t dev
, int flags
, int fmt
,
249 struct satlink_softc
*sc
;
252 sc
= device_lookup_private(&satlink_cd
, minor(dev
));
257 if (sc
->sc_flags
& SATF_ISOPEN
)
260 bus_space_write_1(sc
->sc_iot
, sc
->sc_ioh
, SATLINK_COMMAND
,
263 /* Reset the ring buffer, and start the DMA loop. */
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
);
273 sc
->sc_flags
|= SATF_ISOPEN
;
275 callout_reset(&sc
->sc_ch
, SATLINK_TIMEOUT
, satlinktimeout
, sc
);
281 satlinkclose(dev_t dev
, int flags
, int fmt
,
284 struct satlink_softc
*sc
;
287 sc
= device_lookup_private(&satlink_cd
, minor(dev
));
290 sc
->sc_flags
&= ~SATF_ISOPEN
;
293 isa_dmaabort(sc
->sc_ic
, sc
->sc_drq
);
294 callout_stop(&sc
->sc_ch
);
300 satlinkread(dev_t dev
, struct uio
*uio
, int flags
)
302 struct satlink_softc
*sc
;
303 int error
, s
, count
, sptr
;
306 sc
= device_lookup_private(&satlink_cd
, minor(dev
));
310 /* Wait for data to be available. */
311 while (sc
->sc_sptr
== sc
->sc_uptr
) {
312 if (flags
& O_NONBLOCK
) {
314 return (EWOULDBLOCK
);
316 sc
->sc_flags
|= SATF_DATA
;
317 if ((error
= tsleep(sc
, TTIPRI
| PCATCH
, "satio", 0)) != 0) {
326 /* Compute number of readable bytes. */
327 if (sptr
> sc
->sc_uptr
)
328 count
= sptr
- sc
->sc_uptr
;
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
);
342 sc
->sc_uptr
+= count
;
343 if (sc
->sc_uptr
== sc
->sc_bufsize
)
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
);
358 if (error
!= 0 || wrapcnt
== oresid
)
361 /* ...and the rest. */
363 error
= uiomove(sc
->sc_buf
, count
, uio
);
364 sc
->sc_uptr
+= count
;
365 if (sc
->sc_uptr
== sc
->sc_bufsize
)
372 satlinkioctl(dev_t dev
, u_long cmd
, void *data
, int flags
,
375 struct satlink_softc
*sc
;
377 sc
= device_lookup_private(&satlink_cd
, minor(dev
));
381 bus_space_write_1(sc
->sc_iot
, sc
->sc_ioh
, SATLINK_COMMAND
,
383 sc
->sc_uptr
= isa_dmacount(sc
->sc_ic
, sc
->sc_drq
);
384 sc
->sc_sptr
= sc
->sc_uptr
;
388 memcpy(data
, &sc
->sc_id
, sizeof(sc
->sc_id
));
399 satlinkpoll(dev_t dev
, int events
, struct lwp
*l
)
401 struct satlink_softc
*sc
;
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)
412 /* We're timeout-driven, so must block the clock. */
414 if (sc
->sc_uptr
!= sc
->sc_sptr
)
415 revents
|= events
& (POLLIN
| POLLRDNORM
);
417 selrecord(l
, &sc
->sc_selq
);
424 filt_satlinkrdetach(struct knote
*kn
)
426 struct satlink_softc
*sc
= kn
->kn_hook
;
430 SLIST_REMOVE(&sc
->sc_selq
.sel_klist
, kn
, knote
, kn_selnext
);
435 filt_satlinkread(struct knote
*kn
, long hint
)
437 struct satlink_softc
*sc
= kn
->kn_hook
;
439 if (sc
->sc_uptr
== sc
->sc_sptr
)
442 if (sc
->sc_sptr
> sc
->sc_uptr
)
443 kn
->kn_data
= sc
->sc_sptr
- sc
->sc_uptr
;
445 kn
->kn_data
= (sc
->sc_bufsize
- sc
->sc_uptr
) +
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
;
463 sc
= device_lookup_private(&satlink_cd
, minor(dev
));
465 switch (kn
->kn_filter
) {
467 klist
= &sc
->sc_selq
.sel_klist
;
468 kn
->kn_fop
= &satlinkread_filtops
;
472 klist
= &sc
->sc_selq
.sel_klist
;
473 kn
->kn_fop
= &satlink_seltrue_filtops
;
483 SLIST_INSERT_HEAD(klist
, kn
, kn_selnext
);
490 satlinktimeout(void *arg
)
492 struct satlink_softc
*sc
= arg
;
496 if ((sc
->sc_flags
& SATF_ISOPEN
) == 0)
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
)
508 if (newidx
== sc
->sc_sptr
)
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
;
519 /* Wake up anyone blocked in poll... */
520 selnotify(&sc
->sc_selq
, 0, 0);
523 callout_reset(&sc
->sc_ch
, SATLINK_TIMEOUT
, satlinktimeout
, sc
);