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