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