irframe_tty.c revision 1.19.2.5 1 /* $NetBSD: irframe_tty.c,v 1.19.2.5 2002/06/24 22:10:06 nathanw 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/param.h>
51 #include <sys/lwp.h>
52 #include <sys/proc.h>
53 #include <sys/ioctl.h>
54 #include <sys/tty.h>
55 #include <sys/kernel.h>
56 #include <sys/lock.h>
57 #include <sys/malloc.h>
58 #include <sys/conf.h>
59 #include <sys/systm.h>
60 #include <sys/device.h>
61 #include <sys/file.h>
62 #include <sys/vnode.h>
63 #include <sys/poll.h>
64
65 #include <dev/ir/ir.h>
66 #include <dev/ir/sir.h>
67 #include <dev/ir/irdaio.h>
68 #include <dev/ir/irframevar.h>
69
70 /* Macros to clear/set/test flags. */
71 #define SET(t, f) (t) |= (f)
72 #define CLR(t, f) (t) &= ~(f)
73 #define ISSET(t, f) ((t) & (f))
74
75 #ifdef IRFRAMET_DEBUG
76 #define DPRINTF(x) if (irframetdebug) printf x
77 #define Static
78 int irframetdebug = 0;
79 #else
80 #define DPRINTF(x)
81 #define Static static
82 #endif
83
84 /*****/
85
86 /* Max size with framing. */
87 #define MAX_IRDA_FRAME (2*IRDA_MAX_FRAME_SIZE + IRDA_MAX_EBOFS + 4)
88
89 struct frame {
90 u_char *buf;
91 u_int len;
92 };
93 #define MAXFRAMES 8
94
95 struct irframet_softc {
96 struct irframe_softc sc_irp;
97 struct tty *sc_tp;
98
99 int sc_dongle;
100 int sc_dongle_private;
101
102 int sc_state;
103 #define IRT_RSLP 0x01 /* waiting for data (read) */
104 #if 0
105 #define IRT_WSLP 0x02 /* waiting for data (write) */
106 #define IRT_CLOSING 0x04 /* waiting for output to drain */
107 #endif
108 struct lock sc_wr_lk;
109
110 struct irda_params sc_params;
111
112 u_char* sc_inbuf;
113 int sc_framestate;
114 #define FRAME_OUTSIDE 0
115 #define FRAME_INSIDE 1
116 #define FRAME_ESCAPE 2
117 int sc_inchars;
118 int sc_inFCS;
119 struct callout sc_timeout;
120
121 u_int sc_nframes;
122 u_int sc_framei;
123 u_int sc_frameo;
124 struct frame sc_frames[MAXFRAMES];
125 struct selinfo sc_rsel;
126 };
127
128 /* line discipline methods */
129 int irframetopen(dev_t dev, struct tty *tp);
130 int irframetclose(struct tty *tp, int flag);
131 int irframetioctl(struct tty *tp, u_long cmd, caddr_t data, int flag,
132 struct proc *);
133 int irframetinput(int c, struct tty *tp);
134 int irframetstart(struct tty *tp);
135
136 /* pseudo device init */
137 void irframettyattach(int);
138
139 /* irframe methods */
140 Static int irframet_open(void *h, int flag, int mode, struct proc *p);
141 Static int irframet_close(void *h, int flag, int mode, struct proc *p);
142 Static int irframet_read(void *h, struct uio *uio, int flag);
143 Static int irframet_write(void *h, struct uio *uio, int flag);
144 Static int irframet_poll(void *h, int events, struct proc *p);
145 Static int irframet_set_params(void *h, struct irda_params *params);
146 Static int irframet_get_speeds(void *h, int *speeds);
147 Static int irframet_get_turnarounds(void *h, int *times);
148
149 /* internal */
150 Static int irt_write_frame(struct tty *tp, u_int8_t *buf, size_t len);
151 Static int irt_putc(struct tty *tp, int c);
152 Static void irt_frame(struct irframet_softc *sc, u_char *buf, u_int len);
153 Static void irt_timeout(void *v);
154 Static void irt_ioctl(struct tty *tp, u_long cmd, void *arg);
155 Static void irt_setspeed(struct tty *tp, u_int speed);
156 Static void irt_setline(struct tty *tp, u_int line);
157 Static void irt_delay(struct tty *tp, u_int delay);
158
159 Static const struct irframe_methods irframet_methods = {
160 irframet_open, irframet_close, irframet_read, irframet_write,
161 irframet_poll, irframet_set_params,
162 irframet_get_speeds, irframet_get_turnarounds
163 };
164
165 Static void irts_none(struct tty *tp, u_int speed);
166 Static void irts_tekram(struct tty *tp, u_int speed);
167 Static void irts_jeteye(struct tty *tp, u_int speed);
168 Static void irts_actisys(struct tty *tp, u_int speed);
169 Static void irts_litelink(struct tty *tp, u_int speed);
170 Static void irts_girbil(struct tty *tp, u_int speed);
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 *tp, u_int speed);
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 void
192 irframettyattach(int n)
193 {
194 }
195
196 /*
197 * Line specific open routine for async tty devices.
198 * Attach the given tty to the first available irframe unit.
199 * Called from device open routine or ttioctl.
200 */
201 /* ARGSUSED */
202 int
203 irframetopen(dev_t dev, struct tty *tp)
204 {
205 struct proc *p = curproc; /* XXX */
206 struct irframet_softc *sc;
207 int error, s;
208
209 DPRINTF(("%s\n", __FUNCTION__));
210
211 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
212 return (error);
213
214 s = spltty();
215
216 DPRINTF(("%s: linesw=%p disc=%s\n", __FUNCTION__, tp->t_linesw,
217 tp->t_linesw->l_name));
218 if (strcmp(tp->t_linesw->l_name, "irframe") == 0) { /* XXX */
219 sc = (struct irframet_softc *)tp->t_sc;
220 DPRINTF(("%s: sc=%p sc_tp=%p\n", __FUNCTION__, sc, sc->sc_tp));
221 if (sc != NULL) {
222 splx(s);
223 return (EBUSY);
224 }
225 }
226
227 tp->t_sc = irframe_alloc(sizeof (struct irframet_softc),
228 &irframet_methods, tp);
229 sc = (struct irframet_softc *)tp->t_sc;
230 sc->sc_tp = tp;
231 printf("%s attached at tty%02d\n", sc->sc_irp.sc_dev.dv_xname,
232 minor(tp->t_dev));
233
234 DPRINTF(("%s: set sc=%p\n", __FUNCTION__, sc));
235
236 ttyflush(tp, FREAD | FWRITE);
237
238 sc->sc_dongle = DONGLE_NONE;
239 sc->sc_dongle_private = 0;
240
241 splx(s);
242
243 return (0);
244 }
245
246 /*
247 * Line specific close routine, called from device close routine
248 * and from ttioctl.
249 * Detach the tty from the irframe unit.
250 * Mimics part of ttyclose().
251 */
252 int
253 irframetclose(struct tty *tp, int flag)
254 {
255 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
256 int s;
257
258 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
259
260 s = spltty();
261 ttyflush(tp, FREAD | FWRITE);
262 tp->t_linesw = linesw[0]; /* default line discipline */
263 if (sc != NULL) {
264 tp->t_sc = NULL;
265 printf("%s detached from tty%02d\n", sc->sc_irp.sc_dev.dv_xname,
266 minor(tp->t_dev));
267
268 if (sc->sc_tp == tp)
269 irframe_dealloc(&sc->sc_irp.sc_dev);
270 }
271 splx(s);
272 return (0);
273 }
274
275 /*
276 * Line specific (tty) ioctl routine.
277 * This discipline requires that tty device drivers call
278 * the line specific l_ioctl routine from their ioctl routines.
279 */
280 /* ARGSUSED */
281 int
282 irframetioctl(struct tty *tp, u_long cmd, caddr_t data, int flag,
283 struct proc *p)
284 {
285 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
286 int error;
287 int d;
288
289 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
290
291 if (sc == NULL || tp != sc->sc_tp)
292 return (EPASSTHROUGH);
293
294 error = 0;
295 switch (cmd) {
296 case IRFRAMETTY_GET_DEVICE:
297 *(int *)data = sc->sc_irp.sc_dev.dv_unit;
298 break;
299 case IRFRAMETTY_GET_DONGLE:
300 *(int *)data = sc->sc_dongle;
301 break;
302 case IRFRAMETTY_SET_DONGLE:
303 d = *(int *)data;
304 if (d < 0 || d >= DONGLE_MAX)
305 return (EINVAL);
306 sc->sc_dongle = d;
307 break;
308 default:
309 error = EPASSTHROUGH;
310 break;
311 }
312
313 return (error);
314 }
315
316 /*
317 * Start output on async tty interface.
318 */
319 int
320 irframetstart(struct tty *tp)
321 {
322 /*struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;*/
323 int s;
324
325 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
326
327 s = spltty();
328 if (tp->t_oproc != NULL)
329 (*tp->t_oproc)(tp);
330 splx(s);
331
332 return (0);
333 }
334
335 void
336 irt_frame(struct irframet_softc *sc, u_char *buf, u_int len)
337 {
338 DPRINTF(("%s: nframe=%d framei=%d frameo=%d\n",
339 __FUNCTION__, sc->sc_nframes, sc->sc_framei, sc->sc_frameo));
340
341 if (sc->sc_inbuf == NULL) /* XXX happens if device is closed? */
342 return;
343 if (sc->sc_nframes >= MAXFRAMES) {
344 #ifdef IRFRAMET_DEBUG
345 printf("%s: dropped frame\n", __FUNCTION__);
346 #endif
347 return;
348 }
349 if (sc->sc_frames[sc->sc_framei].buf == NULL)
350 return;
351 memcpy(sc->sc_frames[sc->sc_framei].buf, buf, len);
352 sc->sc_frames[sc->sc_framei].len = len;
353 sc->sc_framei = (sc->sc_framei+1) % MAXFRAMES;
354 sc->sc_nframes++;
355 if (sc->sc_state & IRT_RSLP) {
356 sc->sc_state &= ~IRT_RSLP;
357 DPRINTF(("%s: waking up reader\n", __FUNCTION__));
358 wakeup(sc->sc_frames);
359 }
360 selwakeup(&sc->sc_rsel);
361 }
362
363 void
364 irt_timeout(void *v)
365 {
366 struct irframet_softc *sc = v;
367
368 #ifdef IRFRAMET_DEBUG
369 if (sc->sc_framestate != FRAME_OUTSIDE)
370 printf("%s: input frame timeout\n", __FUNCTION__);
371 #endif
372 sc->sc_framestate = FRAME_OUTSIDE;
373 }
374
375 int
376 irframetinput(int c, struct tty *tp)
377 {
378 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
379
380 c &= 0xff;
381
382 #if IRFRAMET_DEBUG
383 if (irframetdebug > 1)
384 DPRINTF(("%s: tp=%p c=0x%02x\n", __FUNCTION__, tp, c));
385 #endif
386
387 if (sc == NULL || tp != (struct tty *)sc->sc_tp)
388 return (0);
389
390 if (sc->sc_inbuf == NULL)
391 return (0);
392
393 switch (c) {
394 case SIR_BOF:
395 DPRINTF(("%s: BOF\n", __FUNCTION__));
396 sc->sc_framestate = FRAME_INSIDE;
397 sc->sc_inchars = 0;
398 sc->sc_inFCS = INITFCS;
399 break;
400 case SIR_EOF:
401 DPRINTF(("%s: EOF state=%d inchars=%d fcs=0x%04x\n",
402 __FUNCTION__,
403 sc->sc_framestate, sc->sc_inchars, sc->sc_inFCS));
404 if (sc->sc_framestate == FRAME_INSIDE &&
405 sc->sc_inchars >= 4 && sc->sc_inFCS == GOODFCS) {
406 irt_frame(sc, sc->sc_inbuf, sc->sc_inchars - 2);
407 } else if (sc->sc_framestate != FRAME_OUTSIDE) {
408 #ifdef IRFRAMET_DEBUG
409 printf("%s: malformed input frame\n", __FUNCTION__);
410 #endif
411 }
412 sc->sc_framestate = FRAME_OUTSIDE;
413 break;
414 case SIR_CE:
415 DPRINTF(("%s: CE\n", __FUNCTION__));
416 if (sc->sc_framestate == FRAME_INSIDE)
417 sc->sc_framestate = FRAME_ESCAPE;
418 break;
419 default:
420 #if IRFRAMET_DEBUG
421 if (irframetdebug > 1)
422 DPRINTF(("%s: c=0x%02x, inchar=%d state=%d\n", __FUNCTION__, c,
423 sc->sc_inchars, sc->sc_state));
424 #endif
425 if (sc->sc_framestate != FRAME_OUTSIDE) {
426 if (sc->sc_framestate == FRAME_ESCAPE) {
427 sc->sc_framestate = FRAME_INSIDE;
428 c ^= SIR_ESC_BIT;
429 }
430 if (sc->sc_inchars < sc->sc_params.maxsize + 2) {
431 sc->sc_inbuf[sc->sc_inchars++] = c;
432 sc->sc_inFCS = updateFCS(sc->sc_inFCS, c);
433 } else {
434 sc->sc_framestate = FRAME_OUTSIDE;
435 #ifdef IRFRAMET_DEBUG
436 printf("%s: input frame overrun\n",
437 __FUNCTION__);
438 #endif
439 }
440 }
441 break;
442 }
443
444 #if 1
445 if (sc->sc_framestate != FRAME_OUTSIDE) {
446 callout_reset(&sc->sc_timeout, hz/20, irt_timeout, sc);
447 }
448 #endif
449
450 return (0);
451 }
452
453
454 /*** irframe methods ***/
455
456 int
457 irframet_open(void *h, int flag, int mode, struct proc *p)
458 {
459 struct tty *tp = h;
460 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
461
462 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
463
464 sc->sc_params.speed = 0;
465 sc->sc_params.ebofs = IRDA_DEFAULT_EBOFS;
466 sc->sc_params.maxsize = 0;
467 sc->sc_framestate = FRAME_OUTSIDE;
468 sc->sc_nframes = 0;
469 sc->sc_framei = 0;
470 sc->sc_frameo = 0;
471 callout_init(&sc->sc_timeout);
472 lockinit(&sc->sc_wr_lk, PZERO, "irfrtl", 0, 0);
473
474 return (0);
475 }
476
477 int
478 irframet_close(void *h, int flag, int mode, struct proc *p)
479 {
480 struct tty *tp = h;
481 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
482 int i, s;
483
484 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
485
486 callout_stop(&sc->sc_timeout);
487 s = splir();
488 if (sc->sc_inbuf != NULL) {
489 free(sc->sc_inbuf, M_DEVBUF);
490 sc->sc_inbuf = NULL;
491 }
492 for (i = 0; i < MAXFRAMES; i++) {
493 if (sc->sc_frames[i].buf != NULL) {
494 free(sc->sc_frames[i].buf, M_DEVBUF);
495 sc->sc_frames[i].buf = NULL;
496 }
497 }
498 splx(s);
499
500 return (0);
501 }
502
503 int
504 irframet_read(void *h, struct uio *uio, int flag)
505 {
506 struct tty *tp = h;
507 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
508 int error = 0;
509 int s;
510
511 DPRINTF(("%s: resid=%d, iovcnt=%d, offset=%ld\n",
512 __FUNCTION__, uio->uio_resid, uio->uio_iovcnt,
513 (long)uio->uio_offset));
514 DPRINTF(("%s: nframe=%d framei=%d frameo=%d\n",
515 __FUNCTION__, sc->sc_nframes, sc->sc_framei, sc->sc_frameo));
516
517
518 s = splir();
519 while (sc->sc_nframes == 0) {
520 if (flag & IO_NDELAY) {
521 splx(s);
522 return (EWOULDBLOCK);
523 }
524 sc->sc_state |= IRT_RSLP;
525 DPRINTF(("%s: sleep\n", __FUNCTION__));
526 error = tsleep(sc->sc_frames, PZERO | PCATCH, "irtrd", 0);
527 DPRINTF(("%s: woke, error=%d\n", __FUNCTION__, error));
528 if (error) {
529 sc->sc_state &= ~IRT_RSLP;
530 break;
531 }
532 }
533
534 /* Do just one frame transfer per read */
535 if (!error) {
536 if (uio->uio_resid < sc->sc_frames[sc->sc_frameo].len) {
537 DPRINTF(("%s: uio buffer smaller than frame size "
538 "(%d < %d)\n", __FUNCTION__, uio->uio_resid,
539 sc->sc_frames[sc->sc_frameo].len));
540 error = EINVAL;
541 } else {
542 DPRINTF(("%s: moving %d bytes\n", __FUNCTION__,
543 sc->sc_frames[sc->sc_frameo].len));
544 error = uiomove(sc->sc_frames[sc->sc_frameo].buf,
545 sc->sc_frames[sc->sc_frameo].len, uio);
546 DPRINTF(("%s: error=%d\n", __FUNCTION__, error));
547 }
548 sc->sc_frameo = (sc->sc_frameo+1) % MAXFRAMES;
549 sc->sc_nframes--;
550 }
551 splx(s);
552
553 return (error);
554 }
555
556 int
557 irt_putc(struct tty *tp, int c)
558 {
559 int s;
560 int error;
561
562 #if IRFRAMET_DEBUG
563 if (irframetdebug > 3)
564 DPRINTF(("%s: tp=%p c=0x%02x cc=%d\n", __FUNCTION__, tp, c,
565 tp->t_outq.c_cc));
566 #endif
567 if (tp->t_outq.c_cc > tp->t_hiwat) {
568 irframetstart(tp);
569 s = spltty();
570 /*
571 * This can only occur if FLUSHO is set in t_lflag,
572 * or if ttstart/oproc is synchronous (or very fast).
573 */
574 if (tp->t_outq.c_cc <= tp->t_hiwat) {
575 splx(s);
576 goto go;
577 }
578 SET(tp->t_state, TS_ASLEEP);
579 error = ttysleep(tp, &tp->t_outq, TTOPRI | PCATCH, ttyout, 0);
580 splx(s);
581 if (error)
582 return (error);
583 }
584 go:
585 if (putc(c, &tp->t_outq) < 0) {
586 printf("irframe: putc failed\n");
587 return (EIO);
588 }
589 return (0);
590 }
591
592 int
593 irframet_write(void *h, struct uio *uio, int flag)
594 {
595 struct tty *tp = h;
596 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
597 u_int8_t buf[MAX_IRDA_FRAME];
598 int n;
599
600 DPRINTF(("%s: resid=%d, iovcnt=%d, offset=%ld\n",
601 __FUNCTION__, uio->uio_resid, uio->uio_iovcnt,
602 (long)uio->uio_offset));
603
604 n = irda_sir_frame(buf, MAX_IRDA_FRAME, uio, sc->sc_params.ebofs);
605 if (n < 0) {
606 #ifdef IRFRAMET_DEBUG
607 printf("%s: irda_sir_frame() error=%d\n", __FUNCTION__, -n);
608 #endif
609 return (-n);
610 }
611 return (irt_write_frame(tp, buf, n));
612 }
613
614 int
615 irt_write_frame(struct tty *tp, u_int8_t *buf, size_t len)
616 {
617 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
618 int error, i;
619
620 DPRINTF(("%s: tp=%p len=%d\n", __FUNCTION__, tp, len));
621
622 lockmgr(&sc->sc_wr_lk, LK_EXCLUSIVE, NULL);
623 error = 0;
624 for (i = 0; !error && i < len; i++)
625 error = irt_putc(tp, buf[i]);
626 lockmgr(&sc->sc_wr_lk, LK_RELEASE, NULL);
627
628 irframetstart(tp);
629
630 DPRINTF(("%s: done, error=%d\n", __FUNCTION__, error));
631
632 return (error);
633 }
634
635 int
636 irframet_poll(void *h, int events, struct proc *p)
637 {
638 struct tty *tp = h;
639 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
640 int revents = 0;
641 int s;
642
643 DPRINTF(("%s: sc=%p\n", __FUNCTION__, sc));
644
645 s = splir();
646 /* XXX is this a good check? */
647 if (events & (POLLOUT | POLLWRNORM))
648 if (tp->t_outq.c_cc <= tp->t_lowat)
649 revents |= events & (POLLOUT | POLLWRNORM);
650
651 if (events & (POLLIN | POLLRDNORM)) {
652 if (sc->sc_nframes > 0) {
653 DPRINTF(("%s: have data\n", __FUNCTION__));
654 revents |= events & (POLLIN | POLLRDNORM);
655 } else {
656 DPRINTF(("%s: recording select\n", __FUNCTION__));
657 selrecord(p, &sc->sc_rsel);
658 }
659 }
660 splx(s);
661
662 return (revents);
663 }
664
665 int
666 irframet_set_params(void *h, struct irda_params *p)
667 {
668 struct tty *tp = h;
669 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
670 int i;
671
672 DPRINTF(("%s: tp=%p speed=%d ebofs=%d maxsize=%d\n",
673 __FUNCTION__, tp, p->speed, p->ebofs, p->maxsize));
674
675 if (p->speed != sc->sc_params.speed) {
676 /* Checked in irframe.c */
677 lockmgr(&sc->sc_wr_lk, LK_EXCLUSIVE, NULL);
678 irt_dongles[sc->sc_dongle].setspeed(tp, p->speed);
679 lockmgr(&sc->sc_wr_lk, LK_RELEASE, NULL);
680 sc->sc_params.speed = p->speed;
681 }
682
683 /* Max size checked in irframe.c */
684 sc->sc_params.ebofs = p->ebofs;
685 /* Max size checked in irframe.c */
686 if (sc->sc_params.maxsize != p->maxsize) {
687 sc->sc_params.maxsize = p->maxsize;
688 if (sc->sc_inbuf != NULL)
689 free(sc->sc_inbuf, M_DEVBUF);
690 for (i = 0; i < MAXFRAMES; i++)
691 if (sc->sc_frames[i].buf != NULL)
692 free(sc->sc_frames[i].buf, M_DEVBUF);
693 if (sc->sc_params.maxsize != 0) {
694 sc->sc_inbuf = malloc(sc->sc_params.maxsize+2,
695 M_DEVBUF, M_WAITOK);
696 for (i = 0; i < MAXFRAMES; i++)
697 sc->sc_frames[i].buf =
698 malloc(sc->sc_params.maxsize,
699 M_DEVBUF, M_WAITOK);
700 } else {
701 sc->sc_inbuf = NULL;
702 for (i = 0; i < MAXFRAMES; i++)
703 sc->sc_frames[i].buf = NULL;
704 }
705 }
706 sc->sc_framestate = FRAME_OUTSIDE;
707
708 return (0);
709 }
710
711 int
712 irframet_get_speeds(void *h, int *speeds)
713 {
714 struct tty *tp = h;
715 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
716
717 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
718
719 if (sc == NULL) /* during attach */
720 *speeds = IRDA_SPEEDS_SIR;
721 else
722 *speeds = irt_dongles[sc->sc_dongle].speedmask;
723 return (0);
724 }
725
726 int
727 irframet_get_turnarounds(void *h, int *turnarounds)
728 {
729 struct tty *tp = h;
730 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
731
732 DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
733
734 *turnarounds = irt_dongles[sc->sc_dongle].turnmask;
735 return (0);
736 }
737
738 void
739 irt_ioctl(struct tty *tp, u_long cmd, void *arg)
740 {
741 int error;
742 dev_t dev;
743
744 dev = tp->t_dev;
745 error = cdevsw[major(dev)].d_ioctl(dev, cmd, arg, 0, curproc);
746 #ifdef DIAGNOSTIC
747 if (error)
748 printf("irt_ioctl: cmd=0x%08lx error=%d\n", cmd, error);
749 #endif
750 }
751
752 void
753 irt_setspeed(struct tty *tp, u_int speed)
754 {
755 struct termios tt;
756
757 irt_ioctl(tp, TIOCGETA, &tt);
758 tt.c_ispeed = tt.c_ospeed = speed;
759 tt.c_cflag &= ~HUPCL;
760 tt.c_cflag |= CLOCAL;
761 irt_ioctl(tp, TIOCSETAF, &tt);
762 }
763
764 void
765 irt_setline(struct tty *tp, u_int line)
766 {
767 int mline;
768
769 irt_ioctl(tp, TIOCMGET, &mline);
770 mline &= ~(TIOCM_DTR | TIOCM_RTS);
771 mline |= line;
772 irt_ioctl(tp, TIOCMSET, (caddr_t)&mline);
773 }
774
775 void
776 irt_delay(struct tty *tp, u_int ms)
777 {
778 if (cold)
779 delay(ms * 1000);
780 else
781 tsleep(&irt_delay, PZERO, "irtdly", ms * hz / 1000 + 1);
782
783 }
784
785 /**********************************************************************
786 * No dongle
787 **********************************************************************/
788 void
789 irts_none(struct tty *tp, u_int speed)
790 {
791 irt_setspeed(tp, speed);
792 }
793
794 /**********************************************************************
795 * Tekram
796 **********************************************************************/
797 #define TEKRAM_PW 0x10
798
799 #define TEKRAM_115200 (TEKRAM_PW|0x00)
800 #define TEKRAM_57600 (TEKRAM_PW|0x01)
801 #define TEKRAM_38400 (TEKRAM_PW|0x02)
802 #define TEKRAM_19200 (TEKRAM_PW|0x03)
803 #define TEKRAM_9600 (TEKRAM_PW|0x04)
804 #define TEKRAM_2400 (TEKRAM_PW|0x08)
805
806 #define TEKRAM_TV (TEKRAM_PW|0x05)
807
808 void
809 irts_tekram(struct tty *tp, u_int speed)
810 {
811 int s;
812
813 irt_setspeed(tp, 9600);
814 irt_setline(tp, 0);
815 irt_delay(tp, 50);
816
817 irt_setline(tp, TIOCM_RTS);
818 irt_delay(tp, 1);
819
820 irt_setline(tp, TIOCM_DTR | TIOCM_RTS);
821 irt_delay(tp, 1); /* 50 us */
822
823 irt_setline(tp, TIOCM_DTR);
824 irt_delay(tp, 1); /* 7 us */
825
826 switch(speed) {
827 case 115200: s = TEKRAM_115200; break;
828 case 57600: s = TEKRAM_57600; break;
829 case 38400: s = TEKRAM_38400; break;
830 case 19200: s = TEKRAM_19200; break;
831 case 2400: s = TEKRAM_2400; break;
832 default: s = TEKRAM_9600; break;
833 }
834 irt_putc(tp, s);
835 irframetstart(tp);
836
837 irt_delay(tp, 100);
838
839 irt_setline(tp, TIOCM_DTR | TIOCM_RTS);
840 if (speed != 9600)
841 irt_setspeed(tp, speed);
842 irt_delay(tp, 1); /* 50 us */
843 }
844
845 /**********************************************************************
846 * Jeteye
847 **********************************************************************/
848 void
849 irts_jeteye(struct tty *tp, u_int speed)
850 {
851 switch (speed) {
852 case 19200:
853 irt_setline(tp, TIOCM_DTR);
854 break;
855 case 115200:
856 irt_setline(tp, TIOCM_DTR | TIOCM_RTS);
857 break;
858 default: /*9600*/
859 irt_setline(tp, TIOCM_RTS);
860 break;
861 }
862 irt_setspeed(tp, speed);
863 }
864
865 /**********************************************************************
866 * Actisys
867 **********************************************************************/
868 void
869 irts_actisys(struct tty *tp, u_int speed)
870 {
871 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
872 int pulses;
873
874 irt_setspeed(tp, speed);
875
876 switch(speed) {
877 case 19200: pulses=1; break;
878 case 57600: pulses=2; break;
879 case 115200: pulses=3; break;
880 case 38400: pulses=4; break;
881 default: /* 9600 */ pulses=0; break;
882 }
883
884 if (sc->sc_dongle_private == 0) {
885 sc->sc_dongle_private = 1;
886 irt_setline(tp, TIOCM_DTR | TIOCM_RTS);
887 /*
888 * Must wait at least 50ms after initial
889 * power on to charge internal capacitor
890 */
891 irt_delay(tp, 50);
892 }
893 irt_setline(tp, TIOCM_RTS);
894 delay(2);
895 for (;;) {
896 irt_setline(tp, TIOCM_DTR | TIOCM_RTS);
897 delay(2);
898 if (--pulses <= 0)
899 break;
900 irt_setline(tp, TIOCM_DTR);
901 delay(2);
902 }
903 }
904
905 /**********************************************************************
906 * Litelink
907 **********************************************************************/
908 void
909 irts_litelink(struct tty *tp, u_int speed)
910 {
911 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
912 int pulses;
913
914 irt_setspeed(tp, speed);
915
916 switch(speed) {
917 case 57600: pulses=1; break;
918 case 38400: pulses=2; break;
919 case 19200: pulses=3; break;
920 case 9600: pulses=4; break;
921 default: /* 115200 */ pulses=0; break;
922 }
923
924 if (sc->sc_dongle_private == 0) {
925 sc->sc_dongle_private = 1;
926 irt_setline(tp, TIOCM_DTR | TIOCM_RTS);
927 }
928 irt_setline(tp, TIOCM_RTS);
929 irt_delay(tp, 1); /* 15 us */;
930 for (;;) {
931 irt_setline(tp, TIOCM_DTR | TIOCM_RTS);
932 irt_delay(tp, 1); /* 15 us */;
933 if (--pulses <= 0)
934 break;
935 irt_setline(tp, TIOCM_DTR);
936 irt_delay(tp, 1); /* 15 us */;
937 }
938 }
939
940 /**********************************************************************
941 * Girbil
942 **********************************************************************/
943 /* Control register 1 */
944 #define GIRBIL_TXEN 0x01 /* Enable transmitter */
945 #define GIRBIL_RXEN 0x02 /* Enable receiver */
946 #define GIRBIL_ECAN 0x04 /* Cancel self emmited data */
947 #define GIRBIL_ECHO 0x08 /* Echo control characters */
948
949 /* LED Current Register */
950 #define GIRBIL_HIGH 0x20
951 #define GIRBIL_MEDIUM 0x21
952 #define GIRBIL_LOW 0x22
953
954 /* Baud register */
955 #define GIRBIL_2400 0x30
956 #define GIRBIL_4800 0x31
957 #define GIRBIL_9600 0x32
958 #define GIRBIL_19200 0x33
959 #define GIRBIL_38400 0x34
960 #define GIRBIL_57600 0x35
961 #define GIRBIL_115200 0x36
962
963 /* Mode register */
964 #define GIRBIL_IRDA 0x40
965 #define GIRBIL_ASK 0x41
966
967 /* Control register 2 */
968 #define GIRBIL_LOAD 0x51 /* Load the new baud rate value */
969
970 void
971 irts_girbil(struct tty *tp, u_int speed)
972 {
973 int s;
974
975 irt_setspeed(tp, 9600);
976 irt_setline(tp, TIOCM_DTR);
977 irt_delay(tp, 5);
978 irt_setline(tp, TIOCM_RTS);
979 irt_delay(tp, 20);
980 switch(speed) {
981 case 115200: s = GIRBIL_115200; break;
982 case 57600: s = GIRBIL_57600; break;
983 case 38400: s = GIRBIL_38400; break;
984 case 19200: s = GIRBIL_19200; break;
985 case 4800: s = GIRBIL_4800; break;
986 case 2400: s = GIRBIL_2400; break;
987 default: s = GIRBIL_9600; break;
988 }
989 irt_putc(tp, GIRBIL_TXEN|GIRBIL_RXEN);
990 irt_putc(tp, s);
991 irt_putc(tp, GIRBIL_LOAD);
992 irframetstart(tp);
993 irt_delay(tp, 100);
994 irt_setline(tp, TIOCM_DTR | TIOCM_RTS);
995 if (speed != 9600)
996 irt_setspeed(tp, speed);
997 }
998