irframe_tty.c revision 1.42 1 /* $NetBSD: irframe_tty.c,v 1.42 2007/03/06 20:45:59 drochner Exp $ */
2
3 /*
4 * TODO
5 * Test dongle code.
6 */
7
8 /*
9 * Copyright (c) 2001 The NetBSD Foundation, Inc.
10 * All rights reserved.
11 *
12 * This code is derived from software contributed to The NetBSD Foundation
13 * by Lennart Augustsson (lennart (at) augustsson.net) and Tommy Bohlin
14 * (tommy (at) gatespace.com).
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
24 * 3. All advertising materials mentioning features or use of this software
25 * must display the following acknowledgement:
26 * This product includes software developed by the NetBSD
27 * Foundation, Inc. and its contributors.
28 * 4. Neither the name of The NetBSD Foundation nor the names of its
29 * contributors may be used to endorse or promote products derived
30 * from this software without specific prior written permission.
31 *
32 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
33 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
34 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
35 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
36 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
37 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
38 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
39 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
40 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
41 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42 * POSSIBILITY OF SUCH DAMAGE.
43 */
44
45 /*
46 * Loosely based on ppp_tty.c.
47 * Framing and dongle handling written by Tommy Bohlin.
48 */
49
50 #include <sys/cdefs.h>
51 __KERNEL_RCSID(0, "$NetBSD: irframe_tty.c,v 1.42 2007/03/06 20:45:59 drochner Exp $");
52
53 #include <sys/param.h>
54 #include <sys/proc.h>
55 #include <sys/ioctl.h>
56 #include <sys/tty.h>
57 #include <sys/kernel.h>
58 #include <sys/lock.h>
59 #include <sys/malloc.h>
60 #include <sys/conf.h>
61 #include <sys/systm.h>
62 #include <sys/device.h>
63 #include <sys/file.h>
64 #include <sys/vnode.h>
65 #include <sys/poll.h>
66 #include <sys/kauth.h>
67
68 #include <dev/ir/ir.h>
69 #include <dev/ir/sir.h>
70 #include <dev/ir/irdaio.h>
71 #include <dev/ir/irframevar.h>
72
73 #ifdef IRFRAMET_DEBUG
74 #define DPRINTF(x) if (irframetdebug) printf x
75 int irframetdebug = 0;
76 #else
77 #define DPRINTF(x)
78 #endif
79
80 /*****/
81
82 /* Max size with framing. */
83 #define MAX_IRDA_FRAME (2*IRDA_MAX_FRAME_SIZE + IRDA_MAX_EBOFS + 4)
84
85 struct irt_frame {
86 u_char *buf;
87 u_int len;
88 };
89 #define MAXFRAMES 8
90
91 struct irframet_softc {
92 struct irframe_softc sc_irp;
93 struct tty *sc_tp;
94
95 int sc_dongle;
96 int sc_dongle_private;
97
98 int sc_state;
99 #define IRT_RSLP 0x01 /* waiting for data (read) */
100 #if 0
101 #define IRT_WSLP 0x02 /* waiting for data (write) */
102 #define IRT_CLOSING 0x04 /* waiting for output to drain */
103 #endif
104 struct lock sc_wr_lk;
105
106 struct irda_params sc_params;
107
108 u_char* sc_inbuf;
109 int sc_framestate;
110 #define FRAME_OUTSIDE 0
111 #define FRAME_INSIDE 1
112 #define FRAME_ESCAPE 2
113 int sc_inchars;
114 int sc_inFCS;
115 struct callout sc_timeout;
116
117 u_int sc_nframes;
118 u_int sc_framei;
119 u_int sc_frameo;
120 struct irt_frame sc_frames[MAXFRAMES];
121 u_int8_t sc_buffer[MAX_IRDA_FRAME];
122 struct selinfo sc_rsel;
123 /* XXXJRT Nothing selnotify's sc_wsel */
124 struct selinfo sc_wsel;
125 };
126
127 /* line discipline methods */
128 int irframetopen(dev_t, struct tty *);
129 int irframetclose(struct tty *, int);
130 int irframetioctl(struct tty *, u_long, void *, int, struct lwp *);
131 int irframetinput(int, struct tty *);
132 int irframetstart(struct tty *);
133
134 /* pseudo device init */
135 void irframettyattach(int);
136
137 /* irframe methods */
138 static int irframet_open(void *, int, int, struct lwp *);
139 static int irframet_close(void *, int, int, struct lwp *);
140 static int irframet_read(void *, struct uio *, int);
141 static int irframet_write(void *, struct uio *, int);
142 static int irframet_poll(void *, int, struct lwp *);
143 static int irframet_kqfilter(void *, struct knote *);
144
145 static int irframet_set_params(void *, struct irda_params *);
146 static int irframet_get_speeds(void *, int *);
147 static int irframet_get_turnarounds(void *, int *);
148
149 /* internal */
150 static int irt_write_frame(struct tty *, u_int8_t *, size_t);
151 static int irt_putc(struct tty *, int);
152 static void irt_frame(struct irframet_softc *, u_char *, u_int);
153 static void irt_timeout(void *);
154 static void irt_ioctl(struct tty *, u_long, void *);
155 static void irt_setspeed(struct tty *, u_int);
156 static void irt_setline(struct tty *, u_int);
157 static void irt_delay(struct tty *, u_int);
158
159 static const struct irframe_methods irframet_methods = {
160 irframet_open, irframet_close, irframet_read, irframet_write,
161 irframet_poll, irframet_kqfilter, irframet_set_params,
162 irframet_get_speeds, irframet_get_turnarounds
163 };
164
165 static void irts_none(struct tty *, u_int);
166 static void irts_tekram(struct tty *, u_int);
167 static void irts_jeteye(struct tty *, u_int);
168 static void irts_actisys(struct tty *, u_int);
169 static void irts_litelink(struct tty *, u_int);
170 static void irts_girbil(struct tty *, u_int);
171
172 #define NORMAL_SPEEDS (IRDA_SPEEDS_SIR & ~IRDA_SPEED_2400)
173 #define TURNT_POS (IRDA_TURNT_10000 | IRDA_TURNT_5000 | IRDA_TURNT_1000 | \
174 IRDA_TURNT_500 | IRDA_TURNT_100 | IRDA_TURNT_50 | IRDA_TURNT_10)
175 static const struct dongle {
176 void (*setspeed)(struct tty *, u_int);
177 u_int speedmask;
178 u_int turnmask;
179 } irt_dongles[DONGLE_MAX] = {
180 /* Indexed by dongle number from irdaio.h */
181 { irts_none, IRDA_SPEEDS_SIR, IRDA_TURNT_10000 },
182 { irts_tekram, IRDA_SPEEDS_SIR, IRDA_TURNT_10000 },
183 { irts_jeteye, IRDA_SPEED_9600|IRDA_SPEED_19200|IRDA_SPEED_115200,
184 IRDA_TURNT_10000 },
185 { irts_actisys, NORMAL_SPEEDS & ~IRDA_SPEED_38400, TURNT_POS },
186 { irts_actisys, NORMAL_SPEEDS, TURNT_POS },
187 { irts_litelink, NORMAL_SPEEDS, TURNT_POS },
188 { irts_girbil, IRDA_SPEEDS_SIR, IRDA_TURNT_10000 | IRDA_TURNT_5000 },
189 };
190
191 static struct linesw irframet_disc = {
192 .l_name = "irframe",
193 .l_open = irframetopen,
194 .l_close = irframetclose,
195 .l_read = ttyerrio,
196 .l_write = ttyerrio,
197 .l_ioctl = irframetioctl,
198 .l_rint = irframetinput,
199 .l_start = irframetstart,
200 .l_modem = ttymodem,
201 .l_poll = ttyerrpoll
202 };
203
204 /* glue to attach irframe device */
205 static void irframet_attach(struct device *, struct device *, void *);
206 static int irframet_detach(struct device *, int);
207
208 CFATTACH_DECL(irframet, sizeof(struct irframet_softc),
209 NULL, irframet_attach, irframet_detach, NULL);
210
211 void
212 irframettyattach(int n)
213 {
214
215 (void) ttyldisc_attach(&irframet_disc);
216
217 config_cfattach_attach("irframe", &irframet_ca);
218 }
219
220 static void
221 irframet_attach(struct device *parent, struct device *self, void *aux)
222 {
223
224 /* pseudo-device attachment does not print name */
225 printf("%s", self->dv_xname);
226 #if 0 /* XXX can't do it yet because pseudo-devices don't get aux */
227 struct ir_attach_args ia;
228
229 ia.ia_methods = &irframet_methods;
230 ia.ia_handle = aux->xxx;
231
232 irframe_attach(parent, self, &ia);
233 #endif
234 }
235
236 static int
237 irframet_detach(struct device *dev, int flags)
238 {
239
240 return (irframe_detach(dev, flags));
241 }
242
243 /*
244 * Line specific open routine for async tty devices.
245 * Attach the given tty to the first available irframe unit.
246 * Called from device open routine or ttioctl.
247 */
248 /* ARGSUSED */
249 int
250 irframetopen(dev_t dev, struct tty *tp)
251 {
252 struct lwp *l = curlwp; /* XXX */
253 struct irframet_softc *sc;
254 int error, s;
255 struct cfdata *cfdata;
256 struct ir_attach_args ia;
257
258 DPRINTF(("%s\n", __FUNCTION__));
259
260 if ((error = kauth_authorize_device_tty(l->l_cred,
261 KAUTH_DEVICE_TTY_OPEN, tp)))
262 return (error);
263
264 s = spltty();
265
266 DPRINTF(("%s: linesw=%p disc=%s\n", __FUNCTION__, tp->t_linesw,
267 tp->t_linesw->l_name));
268 if (tp->t_linesw == &irframet_disc) {
269 sc = (struct irframet_softc *)tp->t_sc;
270 DPRINTF(("%s: sc=%p sc_tp=%p\n", __FUNCTION__, sc, sc->sc_tp));
271 if (sc != NULL) {
272 splx(s);
273 return (EBUSY);
274 }
275 }
276
277 cfdata = malloc(sizeof(struct cfdata), M_DEVBUF, M_WAITOK);
278 cfdata->cf_name = "irframe";
279 cfdata->cf_atname = "irframet";
280 cfdata->cf_fstate = FSTATE_STAR;
281 cfdata->cf_unit = 0;
282 sc = (struct irframet_softc *)config_attach_pseudo(cfdata);
283
284 /* XXX should be done in irframet_attach() */
285 ia.ia_methods = &irframet_methods;
286 ia.ia_handle = tp;
287 irframe_attach(0, (struct device *)sc, &ia);
288
289 tp->t_sc = sc;
290 sc->sc_tp = tp;
291 printf("%s attached at tty%02d\n", sc->sc_irp.sc_dev.dv_xname,
292 minor(tp->t_dev));
293
294 DPRINTF(("%s: set sc=%p\n", __FUNCTION__, sc));
295
296 ttyflush(tp, FREAD | FWRITE);
297
298 sc->sc_dongle = DONGLE_NONE;
299 sc->sc_dongle_private = 0;
300
301 splx(s);
302
303 return (0);
304 }
305
306 /*
307 * Line specific close routine, called from device close routine
308 * and from ttioctl.
309 * Detach the tty from the irframe unit.
310 * Mimics part of ttyclose().
311 */
312 int
313 irframetclose(struct tty *tp, int flag)
314 {
315 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
316 int s;
317 struct cfdata *cfdata;
318
319 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
320
321 s = spltty();
322 ttyflush(tp, FREAD | FWRITE);
323 ttyldisc_release(tp->t_linesw);
324 tp->t_linesw = ttyldisc_default();
325 if (sc != NULL) {
326 tp->t_sc = NULL;
327 printf("%s detached from tty%02d\n", sc->sc_irp.sc_dev.dv_xname,
328 minor(tp->t_dev));
329
330 if (sc->sc_tp == tp) {
331 cfdata = sc->sc_irp.sc_dev.dv_cfdata;
332 config_detach(&sc->sc_irp.sc_dev, 0);
333 free(cfdata, M_DEVBUF);
334 }
335 }
336 splx(s);
337 return (0);
338 }
339
340 /*
341 * Line specific (tty) ioctl routine.
342 * This discipline requires that tty device drivers call
343 * the line specific l_ioctl routine from their ioctl routines.
344 */
345 /* ARGSUSED */
346 int
347 irframetioctl(struct tty *tp, u_long cmd, void *data, int flag,
348 struct lwp *l)
349 {
350 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
351 int error;
352 int d;
353
354 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
355
356 if (sc == NULL || tp != sc->sc_tp)
357 return (EPASSTHROUGH);
358
359 error = 0;
360 switch (cmd) {
361 case IRFRAMETTY_GET_DEVICE:
362 *(int *)data = device_unit(&sc->sc_irp.sc_dev);
363 break;
364 case IRFRAMETTY_GET_DONGLE:
365 *(int *)data = sc->sc_dongle;
366 break;
367 case IRFRAMETTY_SET_DONGLE:
368 d = *(int *)data;
369 if (d < 0 || d >= DONGLE_MAX)
370 return (EINVAL);
371 sc->sc_dongle = d;
372 break;
373 default:
374 error = EPASSTHROUGH;
375 break;
376 }
377
378 return (error);
379 }
380
381 /*
382 * Start output on async tty interface.
383 */
384 int
385 irframetstart(struct tty *tp)
386 {
387 /*struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;*/
388 int s;
389
390 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
391
392 s = spltty();
393 if (tp->t_oproc != NULL)
394 (*tp->t_oproc)(tp);
395 splx(s);
396
397 return (0);
398 }
399
400 void
401 irt_frame(struct irframet_softc *sc, u_char *tbuf, u_int len)
402 {
403 DPRINTF(("%s: nframe=%d framei=%d frameo=%d\n",
404 __FUNCTION__, sc->sc_nframes, sc->sc_framei, sc->sc_frameo));
405
406 if (sc->sc_inbuf == NULL) /* XXX happens if device is closed? */
407 return;
408 if (sc->sc_nframes >= MAXFRAMES) {
409 #ifdef IRFRAMET_DEBUG
410 printf("%s: dropped frame\n", __FUNCTION__);
411 #endif
412 return;
413 }
414 if (sc->sc_frames[sc->sc_framei].buf == NULL)
415 return;
416 memcpy(sc->sc_frames[sc->sc_framei].buf, tbuf, len);
417 sc->sc_frames[sc->sc_framei].len = len;
418 sc->sc_framei = (sc->sc_framei+1) % MAXFRAMES;
419 sc->sc_nframes++;
420 if (sc->sc_state & IRT_RSLP) {
421 sc->sc_state &= ~IRT_RSLP;
422 DPRINTF(("%s: waking up reader\n", __FUNCTION__));
423 wakeup(sc->sc_frames);
424 }
425 selnotify(&sc->sc_rsel, 0);
426 }
427
428 void
429 irt_timeout(void *v)
430 {
431 struct irframet_softc *sc = v;
432
433 #ifdef IRFRAMET_DEBUG
434 if (sc->sc_framestate != FRAME_OUTSIDE)
435 printf("%s: input frame timeout\n", __FUNCTION__);
436 #endif
437 sc->sc_framestate = FRAME_OUTSIDE;
438 }
439
440 int
441 irframetinput(int c, struct tty *tp)
442 {
443 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
444
445 c &= 0xff;
446
447 #if IRFRAMET_DEBUG
448 if (irframetdebug > 1)
449 DPRINTF(("%s: tp=%p c=0x%02x\n", __FUNCTION__, tp, c));
450 #endif
451
452 if (sc == NULL || tp != (struct tty *)sc->sc_tp)
453 return (0);
454
455 if (sc->sc_inbuf == NULL)
456 return (0);
457
458 switch (c) {
459 case SIR_BOF:
460 DPRINTF(("%s: BOF\n", __FUNCTION__));
461 sc->sc_framestate = FRAME_INSIDE;
462 sc->sc_inchars = 0;
463 sc->sc_inFCS = INITFCS;
464 break;
465 case SIR_EOF:
466 DPRINTF(("%s: EOF state=%d inchars=%d fcs=0x%04x\n",
467 __FUNCTION__,
468 sc->sc_framestate, sc->sc_inchars, sc->sc_inFCS));
469 if (sc->sc_framestate == FRAME_INSIDE &&
470 sc->sc_inchars >= 4 && sc->sc_inFCS == GOODFCS) {
471 irt_frame(sc, sc->sc_inbuf, sc->sc_inchars - 2);
472 } else if (sc->sc_framestate != FRAME_OUTSIDE) {
473 #ifdef IRFRAMET_DEBUG
474 printf("%s: malformed input frame\n", __FUNCTION__);
475 #endif
476 }
477 sc->sc_framestate = FRAME_OUTSIDE;
478 break;
479 case SIR_CE:
480 DPRINTF(("%s: CE\n", __FUNCTION__));
481 if (sc->sc_framestate == FRAME_INSIDE)
482 sc->sc_framestate = FRAME_ESCAPE;
483 break;
484 default:
485 #if IRFRAMET_DEBUG
486 if (irframetdebug > 1)
487 DPRINTF(("%s: c=0x%02x, inchar=%d state=%d\n", __FUNCTION__, c,
488 sc->sc_inchars, sc->sc_state));
489 #endif
490 if (sc->sc_framestate != FRAME_OUTSIDE) {
491 if (sc->sc_framestate == FRAME_ESCAPE) {
492 sc->sc_framestate = FRAME_INSIDE;
493 c ^= SIR_ESC_BIT;
494 }
495 if (sc->sc_inchars < sc->sc_params.maxsize + 2) {
496 sc->sc_inbuf[sc->sc_inchars++] = c;
497 sc->sc_inFCS = updateFCS(sc->sc_inFCS, c);
498 } else {
499 sc->sc_framestate = FRAME_OUTSIDE;
500 #ifdef IRFRAMET_DEBUG
501 printf("%s: input frame overrun\n",
502 __FUNCTION__);
503 #endif
504 }
505 }
506 break;
507 }
508
509 #if 1
510 if (sc->sc_framestate != FRAME_OUTSIDE) {
511 callout_reset(&sc->sc_timeout, hz/20, irt_timeout, sc);
512 }
513 #endif
514
515 return (0);
516 }
517
518
519 /*** irframe methods ***/
520
521 int
522 irframet_open(void *h, int flag, int mode,
523 struct lwp *l)
524 {
525 struct tty *tp = h;
526 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
527
528 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
529
530 sc->sc_params.speed = 0;
531 sc->sc_params.ebofs = IRDA_DEFAULT_EBOFS;
532 sc->sc_params.maxsize = 0;
533 sc->sc_framestate = FRAME_OUTSIDE;
534 sc->sc_nframes = 0;
535 sc->sc_framei = 0;
536 sc->sc_frameo = 0;
537 callout_init(&sc->sc_timeout);
538 lockinit(&sc->sc_wr_lk, PZERO, "irfrtl", 0, 0);
539
540 return (0);
541 }
542
543 int
544 irframet_close(void *h, int flag, int mode,
545 struct lwp *l)
546 {
547 struct tty *tp = h;
548 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
549 int i, s;
550
551 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
552
553 callout_stop(&sc->sc_timeout);
554 s = splir();
555 if (sc->sc_inbuf != NULL) {
556 free(sc->sc_inbuf, M_DEVBUF);
557 sc->sc_inbuf = NULL;
558 }
559 for (i = 0; i < MAXFRAMES; i++) {
560 if (sc->sc_frames[i].buf != NULL) {
561 free(sc->sc_frames[i].buf, M_DEVBUF);
562 sc->sc_frames[i].buf = NULL;
563 }
564 }
565 splx(s);
566
567 return (0);
568 }
569
570 int
571 irframet_read(void *h, struct uio *uio, int flag)
572 {
573 struct tty *tp = h;
574 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
575 int error = 0;
576 int s;
577
578 DPRINTF(("%s: resid=%zd, iovcnt=%d, offset=%ld\n",
579 __FUNCTION__, uio->uio_resid, uio->uio_iovcnt,
580 (long)uio->uio_offset));
581 DPRINTF(("%s: nframe=%d framei=%d frameo=%d\n",
582 __FUNCTION__, sc->sc_nframes, sc->sc_framei, sc->sc_frameo));
583
584
585 s = splir();
586 while (sc->sc_nframes == 0) {
587 if (flag & IO_NDELAY) {
588 splx(s);
589 return (EWOULDBLOCK);
590 }
591 sc->sc_state |= IRT_RSLP;
592 DPRINTF(("%s: sleep\n", __FUNCTION__));
593 error = tsleep(sc->sc_frames, PZERO | PCATCH, "irtrd", 0);
594 DPRINTF(("%s: woke, error=%d\n", __FUNCTION__, error));
595 if (error) {
596 sc->sc_state &= ~IRT_RSLP;
597 break;
598 }
599 }
600
601 /* Do just one frame transfer per read */
602 if (!error) {
603 if (uio->uio_resid < sc->sc_frames[sc->sc_frameo].len) {
604 DPRINTF(("%s: uio buffer smaller than frame size "
605 "(%zd < %d)\n", __FUNCTION__, uio->uio_resid,
606 sc->sc_frames[sc->sc_frameo].len));
607 error = EINVAL;
608 } else {
609 DPRINTF(("%s: moving %d bytes\n", __FUNCTION__,
610 sc->sc_frames[sc->sc_frameo].len));
611 error = uiomove(sc->sc_frames[sc->sc_frameo].buf,
612 sc->sc_frames[sc->sc_frameo].len, uio);
613 DPRINTF(("%s: error=%d\n", __FUNCTION__, error));
614 }
615 sc->sc_frameo = (sc->sc_frameo+1) % MAXFRAMES;
616 sc->sc_nframes--;
617 }
618 splx(s);
619
620 return (error);
621 }
622
623 int
624 irt_putc(struct tty *tp, int c)
625 {
626 int s;
627 int error;
628
629 #if IRFRAMET_DEBUG
630 if (irframetdebug > 3)
631 DPRINTF(("%s: tp=%p c=0x%02x cc=%d\n", __FUNCTION__, tp, c,
632 tp->t_outq.c_cc));
633 #endif
634 if (tp->t_outq.c_cc > tp->t_hiwat) {
635 irframetstart(tp);
636 s = spltty();
637 /*
638 * This can only occur if FLUSHO is set in t_lflag,
639 * or if ttstart/oproc is synchronous (or very fast).
640 */
641 if (tp->t_outq.c_cc <= tp->t_hiwat) {
642 splx(s);
643 goto go;
644 }
645 SET(tp->t_state, TS_ASLEEP);
646 error = ttysleep(tp, &tp->t_outq, TTOPRI | PCATCH, ttyout, 0);
647 splx(s);
648 if (error)
649 return (error);
650 }
651 go:
652 if (putc(c, &tp->t_outq) < 0) {
653 printf("irframe: putc failed\n");
654 return (EIO);
655 }
656 return (0);
657 }
658
659 int
660 irframet_write(void *h, struct uio *uio, int flag)
661 {
662 struct tty *tp = h;
663 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
664 int n;
665
666 DPRINTF(("%s: resid=%zd, iovcnt=%d, offset=%ld\n",
667 __FUNCTION__, uio->uio_resid, uio->uio_iovcnt,
668 (long)uio->uio_offset));
669
670 n = irda_sir_frame(sc->sc_buffer, sizeof(sc->sc_buffer), uio,
671 sc->sc_params.ebofs);
672 if (n < 0) {
673 #ifdef IRFRAMET_DEBUG
674 printf("%s: irda_sir_frame() error=%d\n", __FUNCTION__, -n);
675 #endif
676 return (-n);
677 }
678 return (irt_write_frame(tp, sc->sc_buffer, n));
679 }
680
681 int
682 irt_write_frame(struct tty *tp, u_int8_t *tbuf, size_t len)
683 {
684 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
685 int error, i;
686
687 DPRINTF(("%s: tp=%p len=%zd\n", __FUNCTION__, tp, len));
688
689 lockmgr(&sc->sc_wr_lk, LK_EXCLUSIVE, NULL);
690 error = 0;
691 for (i = 0; !error && i < len; i++)
692 error = irt_putc(tp, tbuf[i]);
693 lockmgr(&sc->sc_wr_lk, LK_RELEASE, NULL);
694
695 irframetstart(tp);
696
697 DPRINTF(("%s: done, error=%d\n", __FUNCTION__, error));
698
699 return (error);
700 }
701
702 int
703 irframet_poll(void *h, int events, struct lwp *l)
704 {
705 struct tty *tp = h;
706 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
707 int revents = 0;
708 int s;
709
710 DPRINTF(("%s: sc=%p\n", __FUNCTION__, sc));
711
712 s = splir();
713 /* XXX is this a good check? */
714 if (events & (POLLOUT | POLLWRNORM))
715 if (tp->t_outq.c_cc <= tp->t_lowat)
716 revents |= events & (POLLOUT | POLLWRNORM);
717
718 if (events & (POLLIN | POLLRDNORM)) {
719 if (sc->sc_nframes > 0) {
720 DPRINTF(("%s: have data\n", __FUNCTION__));
721 revents |= events & (POLLIN | POLLRDNORM);
722 } else {
723 DPRINTF(("%s: recording select\n", __FUNCTION__));
724 selrecord(l, &sc->sc_rsel);
725 }
726 }
727 splx(s);
728
729 return (revents);
730 }
731
732 static void
733 filt_irframetrdetach(struct knote *kn)
734 {
735 struct tty *tp = kn->kn_hook;
736 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
737 int s;
738
739 s = splir();
740 SLIST_REMOVE(&sc->sc_rsel.sel_klist, kn, knote, kn_selnext);
741 splx(s);
742 }
743
744 static int
745 filt_irframetread(struct knote *kn, long hint)
746 {
747 struct tty *tp = kn->kn_hook;
748 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
749
750 kn->kn_data = sc->sc_nframes;
751 return (kn->kn_data > 0);
752 }
753
754 static void
755 filt_irframetwdetach(struct knote *kn)
756 {
757 struct tty *tp = kn->kn_hook;
758 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
759 int s;
760
761 s = splir();
762 SLIST_REMOVE(&sc->sc_wsel.sel_klist, kn, knote, kn_selnext);
763 splx(s);
764 }
765
766 static int
767 filt_irframetwrite(struct knote *kn, long hint)
768 {
769 struct tty *tp = kn->kn_hook;
770
771 /* XXX double-check this */
772
773 if (tp->t_outq.c_cc <= tp->t_lowat) {
774 kn->kn_data = tp->t_lowat - tp->t_outq.c_cc;
775 return (1);
776 }
777
778 kn->kn_data = 0;
779 return (0);
780 }
781
782 static const struct filterops irframetread_filtops =
783 { 1, NULL, filt_irframetrdetach, filt_irframetread };
784 static const struct filterops irframetwrite_filtops =
785 { 1, NULL, filt_irframetwdetach, filt_irframetwrite };
786
787 int
788 irframet_kqfilter(void *h, struct knote *kn)
789 {
790 struct tty *tp = h;
791 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
792 struct klist *klist;
793 int s;
794
795 switch (kn->kn_filter) {
796 case EVFILT_READ:
797 klist = &sc->sc_rsel.sel_klist;
798 kn->kn_fop = &irframetread_filtops;
799 break;
800 case EVFILT_WRITE:
801 klist = &sc->sc_wsel.sel_klist;
802 kn->kn_fop = &irframetwrite_filtops;
803 break;
804 default:
805 return (1);
806 }
807
808 kn->kn_hook = tp;
809
810 s = splir();
811 SLIST_INSERT_HEAD(klist, kn, kn_selnext);
812 splx(s);
813
814 return (0);
815 }
816
817 int
818 irframet_set_params(void *h, struct irda_params *p)
819 {
820 struct tty *tp = h;
821 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
822 int i;
823
824 DPRINTF(("%s: tp=%p speed=%d ebofs=%d maxsize=%d\n",
825 __FUNCTION__, tp, p->speed, p->ebofs, p->maxsize));
826
827 if (p->speed != sc->sc_params.speed) {
828 /* Checked in irframe.c */
829 lockmgr(&sc->sc_wr_lk, LK_EXCLUSIVE, NULL);
830 irt_dongles[sc->sc_dongle].setspeed(tp, p->speed);
831 lockmgr(&sc->sc_wr_lk, LK_RELEASE, NULL);
832 sc->sc_params.speed = p->speed;
833 }
834
835 /* Max size checked in irframe.c */
836 sc->sc_params.ebofs = p->ebofs;
837 /* Max size checked in irframe.c */
838 if (sc->sc_params.maxsize != p->maxsize) {
839 sc->sc_params.maxsize = p->maxsize;
840 if (sc->sc_inbuf != NULL)
841 free(sc->sc_inbuf, M_DEVBUF);
842 for (i = 0; i < MAXFRAMES; i++)
843 if (sc->sc_frames[i].buf != NULL)
844 free(sc->sc_frames[i].buf, M_DEVBUF);
845 if (sc->sc_params.maxsize != 0) {
846 sc->sc_inbuf = malloc(sc->sc_params.maxsize+2,
847 M_DEVBUF, M_WAITOK);
848 for (i = 0; i < MAXFRAMES; i++)
849 sc->sc_frames[i].buf =
850 malloc(sc->sc_params.maxsize,
851 M_DEVBUF, M_WAITOK);
852 } else {
853 sc->sc_inbuf = NULL;
854 for (i = 0; i < MAXFRAMES; i++)
855 sc->sc_frames[i].buf = NULL;
856 }
857 }
858 sc->sc_framestate = FRAME_OUTSIDE;
859
860 return (0);
861 }
862
863 int
864 irframet_get_speeds(void *h, int *speeds)
865 {
866 struct tty *tp = h;
867 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
868
869 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
870
871 if (sc == NULL) /* during attach */
872 *speeds = IRDA_SPEEDS_SIR;
873 else
874 *speeds = irt_dongles[sc->sc_dongle].speedmask;
875 return (0);
876 }
877
878 int
879 irframet_get_turnarounds(void *h, int *turnarounds)
880 {
881 struct tty *tp = h;
882 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
883
884 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
885
886 *turnarounds = irt_dongles[sc->sc_dongle].turnmask;
887 return (0);
888 }
889
890 void
891 irt_ioctl(struct tty *tp, u_long cmd, void *arg)
892 {
893 const struct cdevsw *cdev;
894 int error;
895 dev_t dev;
896
897 dev = tp->t_dev;
898 cdev = cdevsw_lookup(dev);
899 if (cdev != NULL)
900 error = (*cdev->d_ioctl)(dev, cmd, arg, 0, curlwp);
901 else
902 error = ENXIO;
903 #ifdef DIAGNOSTIC
904 if (error)
905 printf("irt_ioctl: cmd=0x%08lx error=%d\n", cmd, error);
906 #endif
907 }
908
909 void
910 irt_setspeed(struct tty *tp, u_int speed)
911 {
912 struct termios tt;
913
914 irt_ioctl(tp, TIOCGETA, &tt);
915 tt.c_ispeed = tt.c_ospeed = speed;
916 tt.c_cflag &= ~HUPCL;
917 tt.c_cflag |= CLOCAL;
918 irt_ioctl(tp, TIOCSETAF, &tt);
919 }
920
921 void
922 irt_setline(struct tty *tp, u_int line)
923 {
924 int mline;
925
926 irt_ioctl(tp, TIOCMGET, &mline);
927 mline &= ~(TIOCM_DTR | TIOCM_RTS);
928 mline |= line;
929 irt_ioctl(tp, TIOCMSET, (void *)&mline);
930 }
931
932 void
933 irt_delay(struct tty *tp, u_int ms)
934 {
935 if (cold)
936 delay(ms * 1000);
937 else
938 tsleep(&irt_delay, PZERO, "irtdly", ms * hz / 1000 + 1);
939
940 }
941
942 /**********************************************************************
943 * No dongle
944 **********************************************************************/
945 void
946 irts_none(struct tty *tp, u_int speed)
947 {
948 irt_setspeed(tp, speed);
949 }
950
951 /**********************************************************************
952 * Tekram
953 **********************************************************************/
954 #define TEKRAM_PW 0x10
955
956 #define TEKRAM_115200 (TEKRAM_PW|0x00)
957 #define TEKRAM_57600 (TEKRAM_PW|0x01)
958 #define TEKRAM_38400 (TEKRAM_PW|0x02)
959 #define TEKRAM_19200 (TEKRAM_PW|0x03)
960 #define TEKRAM_9600 (TEKRAM_PW|0x04)
961 #define TEKRAM_2400 (TEKRAM_PW|0x08)
962
963 #define TEKRAM_TV (TEKRAM_PW|0x05)
964
965 void
966 irts_tekram(struct tty *tp, u_int speed)
967 {
968 int s;
969
970 irt_setspeed(tp, 9600);
971 irt_setline(tp, 0);
972 irt_delay(tp, 50);
973
974 irt_setline(tp, TIOCM_RTS);
975 irt_delay(tp, 1);
976
977 irt_setline(tp, TIOCM_DTR | TIOCM_RTS);
978 irt_delay(tp, 1); /* 50 us */
979
980 irt_setline(tp, TIOCM_DTR);
981 irt_delay(tp, 1); /* 7 us */
982
983 switch(speed) {
984 case 115200: s = TEKRAM_115200; break;
985 case 57600: s = TEKRAM_57600; break;
986 case 38400: s = TEKRAM_38400; break;
987 case 19200: s = TEKRAM_19200; break;
988 case 2400: s = TEKRAM_2400; break;
989 default: s = TEKRAM_9600; break;
990 }
991 irt_putc(tp, s);
992 irframetstart(tp);
993
994 irt_delay(tp, 100);
995
996 irt_setline(tp, TIOCM_DTR | TIOCM_RTS);
997 if (speed != 9600)
998 irt_setspeed(tp, speed);
999 irt_delay(tp, 1); /* 50 us */
1000 }
1001
1002 /**********************************************************************
1003 * Jeteye
1004 **********************************************************************/
1005 void
1006 irts_jeteye(struct tty *tp, u_int speed)
1007 {
1008 switch (speed) {
1009 case 19200:
1010 irt_setline(tp, TIOCM_DTR);
1011 break;
1012 case 115200:
1013 irt_setline(tp, TIOCM_DTR | TIOCM_RTS);
1014 break;
1015 default: /*9600*/
1016 irt_setline(tp, TIOCM_RTS);
1017 break;
1018 }
1019 irt_setspeed(tp, speed);
1020 }
1021
1022 /**********************************************************************
1023 * Actisys
1024 **********************************************************************/
1025 void
1026 irts_actisys(struct tty *tp, u_int speed)
1027 {
1028 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
1029 int pulses;
1030
1031 irt_setspeed(tp, speed);
1032
1033 switch(speed) {
1034 case 19200: pulses=1; break;
1035 case 57600: pulses=2; break;
1036 case 115200: pulses=3; break;
1037 case 38400: pulses=4; break;
1038 default: /* 9600 */ pulses=0; break;
1039 }
1040
1041 if (sc->sc_dongle_private == 0) {
1042 sc->sc_dongle_private = 1;
1043 irt_setline(tp, TIOCM_DTR | TIOCM_RTS);
1044 /*
1045 * Must wait at least 50ms after initial
1046 * power on to charge internal capacitor
1047 */
1048 irt_delay(tp, 50);
1049 }
1050 irt_setline(tp, TIOCM_RTS);
1051 delay(2);
1052 for (;;) {
1053 irt_setline(tp, TIOCM_DTR | TIOCM_RTS);
1054 delay(2);
1055 if (--pulses <= 0)
1056 break;
1057 irt_setline(tp, TIOCM_DTR);
1058 delay(2);
1059 }
1060 }
1061
1062 /**********************************************************************
1063 * Litelink
1064 **********************************************************************/
1065 void
1066 irts_litelink(struct tty *tp, u_int speed)
1067 {
1068 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
1069 int pulses;
1070
1071 irt_setspeed(tp, speed);
1072
1073 switch(speed) {
1074 case 57600: pulses=1; break;
1075 case 38400: pulses=2; break;
1076 case 19200: pulses=3; break;
1077 case 9600: pulses=4; break;
1078 default: /* 115200 */ pulses=0; break;
1079 }
1080
1081 if (sc->sc_dongle_private == 0) {
1082 sc->sc_dongle_private = 1;
1083 irt_setline(tp, TIOCM_DTR | TIOCM_RTS);
1084 }
1085 irt_setline(tp, TIOCM_RTS);
1086 irt_delay(tp, 1); /* 15 us */;
1087 for (;;) {
1088 irt_setline(tp, TIOCM_DTR | TIOCM_RTS);
1089 irt_delay(tp, 1); /* 15 us */;
1090 if (--pulses <= 0)
1091 break;
1092 irt_setline(tp, TIOCM_DTR);
1093 irt_delay(tp, 1); /* 15 us */;
1094 }
1095 }
1096
1097 /**********************************************************************
1098 * Girbil
1099 **********************************************************************/
1100 /* Control register 1 */
1101 #define GIRBIL_TXEN 0x01 /* Enable transmitter */
1102 #define GIRBIL_RXEN 0x02 /* Enable receiver */
1103 #define GIRBIL_ECAN 0x04 /* Cancel self emmited data */
1104 #define GIRBIL_ECHO 0x08 /* Echo control characters */
1105
1106 /* LED Current Register */
1107 #define GIRBIL_HIGH 0x20
1108 #define GIRBIL_MEDIUM 0x21
1109 #define GIRBIL_LOW 0x22
1110
1111 /* Baud register */
1112 #define GIRBIL_2400 0x30
1113 #define GIRBIL_4800 0x31
1114 #define GIRBIL_9600 0x32
1115 #define GIRBIL_19200 0x33
1116 #define GIRBIL_38400 0x34
1117 #define GIRBIL_57600 0x35
1118 #define GIRBIL_115200 0x36
1119
1120 /* Mode register */
1121 #define GIRBIL_IRDA 0x40
1122 #define GIRBIL_ASK 0x41
1123
1124 /* Control register 2 */
1125 #define GIRBIL_LOAD 0x51 /* Load the new baud rate value */
1126
1127 void
1128 irts_girbil(struct tty *tp, u_int speed)
1129 {
1130 int s;
1131
1132 irt_setspeed(tp, 9600);
1133 irt_setline(tp, TIOCM_DTR);
1134 irt_delay(tp, 5);
1135 irt_setline(tp, TIOCM_RTS);
1136 irt_delay(tp, 20);
1137 switch(speed) {
1138 case 115200: s = GIRBIL_115200; break;
1139 case 57600: s = GIRBIL_57600; break;
1140 case 38400: s = GIRBIL_38400; break;
1141 case 19200: s = GIRBIL_19200; break;
1142 case 4800: s = GIRBIL_4800; break;
1143 case 2400: s = GIRBIL_2400; break;
1144 default: s = GIRBIL_9600; break;
1145 }
1146 irt_putc(tp, GIRBIL_TXEN|GIRBIL_RXEN);
1147 irt_putc(tp, s);
1148 irt_putc(tp, GIRBIL_LOAD);
1149 irframetstart(tp);
1150 irt_delay(tp, 100);
1151 irt_setline(tp, TIOCM_DTR | TIOCM_RTS);
1152 if (speed != 9600)
1153 irt_setspeed(tp, speed);
1154 }
1155