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