xref: /netbsd-src/sys/dev/ir/irframe_tty.c (revision 8b0f9554ff8762542c4defc4f70e1eb76fb508fa)
1 /*	$NetBSD: irframe_tty.c,v 1.50 2007/12/15 00:39:28 perry 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.50 2007/12/15 00:39:28 perry 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/mutex.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 	kmutex_t 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", __func__));
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", __func__, 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", __func__, 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", __func__, 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", __func__, 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", __func__, 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", __func__, 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 		 __func__, 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", __func__);
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", __func__));
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", __func__);
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", __func__, 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", __func__));
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 			 __func__,
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", __func__);
484 #endif
485 		}
486 		sc->sc_framestate = FRAME_OUTSIDE;
487 		break;
488 	case SIR_CE:
489 		DPRINTF(("%s: CE\n", __func__));
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", __func__, 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 				       __func__);
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 	static bool again;
537 
538 	DPRINTF(("%s: tp=%p\n", __func__, tp));
539 
540 	sc->sc_params.speed = 0;
541 	sc->sc_params.ebofs = IRDA_DEFAULT_EBOFS;
542 	sc->sc_params.maxsize = 0;
543 	sc->sc_framestate = FRAME_OUTSIDE;
544 	sc->sc_nframes = 0;
545 	sc->sc_framei = 0;
546 	sc->sc_frameo = 0;
547 
548 	/* XXX */
549 	if (!again) {
550 		again = true;
551 		callout_init(&sc->sc_timeout, 0);
552 		mutex_init(&sc->sc_wr_lk, MUTEX_DEFAULT, IPL_NONE);
553 	}
554 
555 	return (0);
556 }
557 
558 int
559 irframet_close(void *h, int flag, int mode,
560     struct lwp *l)
561 {
562 	struct tty *tp = h;
563 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
564 	int i, s;
565 
566 	DPRINTF(("%s: tp=%p\n", __func__, tp));
567 
568 	callout_stop(&sc->sc_timeout);
569 	s = splir();
570 	if (sc->sc_inbuf != NULL) {
571 		free(sc->sc_inbuf, M_DEVBUF);
572 		sc->sc_inbuf = NULL;
573 	}
574 	for (i = 0; i < MAXFRAMES; i++) {
575 		if (sc->sc_frames[i].buf != NULL) {
576 			free(sc->sc_frames[i].buf, M_DEVBUF);
577 			sc->sc_frames[i].buf = NULL;
578 		}
579 	}
580 	splx(s);
581 
582 	return (0);
583 }
584 
585 int
586 irframet_read(void *h, struct uio *uio, int flag)
587 {
588 	struct tty *tp = h;
589 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
590 	int error = 0;
591 	int s;
592 
593 	DPRINTF(("%s: resid=%zd, iovcnt=%d, offset=%ld\n",
594 		 __func__, uio->uio_resid, uio->uio_iovcnt,
595 		 (long)uio->uio_offset));
596 	DPRINTF(("%s: nframe=%d framei=%d frameo=%d\n",
597 		 __func__, sc->sc_nframes, sc->sc_framei, sc->sc_frameo));
598 
599 
600 	s = splir();
601 	while (sc->sc_nframes == 0) {
602 		if (flag & IO_NDELAY) {
603 			splx(s);
604 			return (EWOULDBLOCK);
605 		}
606 		sc->sc_state |= IRT_RSLP;
607 		DPRINTF(("%s: sleep\n", __func__));
608 		error = tsleep(sc->sc_frames, PZERO | PCATCH, "irtrd", 0);
609 		DPRINTF(("%s: woke, error=%d\n", __func__, error));
610 		if (error) {
611 			sc->sc_state &= ~IRT_RSLP;
612 			break;
613 		}
614 	}
615 
616 	/* Do just one frame transfer per read */
617 	if (!error) {
618 		if (uio->uio_resid < sc->sc_frames[sc->sc_frameo].len) {
619 			DPRINTF(("%s: uio buffer smaller than frame size "
620 				 "(%zd < %d)\n", __func__, uio->uio_resid,
621 				 sc->sc_frames[sc->sc_frameo].len));
622 			error = EINVAL;
623 		} else {
624 			DPRINTF(("%s: moving %d bytes\n", __func__,
625 				 sc->sc_frames[sc->sc_frameo].len));
626 			error = uiomove(sc->sc_frames[sc->sc_frameo].buf,
627 					sc->sc_frames[sc->sc_frameo].len, uio);
628 			DPRINTF(("%s: error=%d\n", __func__, error));
629 		}
630 		sc->sc_frameo = (sc->sc_frameo+1) % MAXFRAMES;
631 		sc->sc_nframes--;
632 	}
633 	splx(s);
634 
635 	return (error);
636 }
637 
638 int
639 irt_putc(struct tty *tp, int c)
640 {
641 	int error;
642 
643 #if IRFRAMET_DEBUG
644 	if (irframetdebug > 3)
645 		DPRINTF(("%s: tp=%p c=0x%02x cc=%d\n", __func__, tp, c,
646 			 tp->t_outq.c_cc));
647 #endif
648 	if (tp->t_outq.c_cc > tp->t_hiwat) {
649 		irframetstart(tp);
650 		mutex_spin_enter(&tty_lock);
651 		/*
652 		 * This can only occur if FLUSHO is set in t_lflag,
653 		 * or if ttstart/oproc is synchronous (or very fast).
654 		 */
655 		if (tp->t_outq.c_cc <= tp->t_hiwat) {
656 			mutex_spin_exit(&tty_lock);
657 			goto go;
658 		}
659 		error = ttysleep(tp, &tp->t_outq.c_cv, true, 0);
660 		mutex_spin_exit(&tty_lock);
661 		if (error)
662 			return (error);
663 	}
664  go:
665 	if (putc(c, &tp->t_outq) < 0) {
666 		printf("irframe: putc failed\n");
667 		return (EIO);
668 	}
669 	return (0);
670 }
671 
672 int
673 irframet_write(void *h, struct uio *uio, int flag)
674 {
675 	struct tty *tp = h;
676 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
677 	int n;
678 
679 	DPRINTF(("%s: resid=%zd, iovcnt=%d, offset=%ld\n",
680 		 __func__, uio->uio_resid, uio->uio_iovcnt,
681 		 (long)uio->uio_offset));
682 
683 	n = irda_sir_frame(sc->sc_buffer, sizeof(sc->sc_buffer), uio,
684 	    sc->sc_params.ebofs);
685 	if (n < 0) {
686 #ifdef IRFRAMET_DEBUG
687 		printf("%s: irda_sir_frame() error=%d\n", __func__, -n);
688 #endif
689 		return (-n);
690 	}
691 	return (irt_write_frame(tp, sc->sc_buffer, n));
692 }
693 
694 int
695 irt_write_frame(struct tty *tp, u_int8_t *tbuf, size_t len)
696 {
697 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
698 	int error, i;
699 
700 	DPRINTF(("%s: tp=%p len=%zd\n", __func__, tp, len));
701 
702 	mutex_enter(&sc->sc_wr_lk);
703 	error = 0;
704 	for (i = 0; !error && i < len; i++)
705 		error = irt_putc(tp, tbuf[i]);
706 	mutex_exit(&sc->sc_wr_lk);
707 
708 	irframetstart(tp);
709 
710 	DPRINTF(("%s: done, error=%d\n", __func__, error));
711 
712 	return (error);
713 }
714 
715 int
716 irframet_poll(void *h, int events, struct lwp *l)
717 {
718 	struct tty *tp = h;
719 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
720 	int revents = 0;
721 	int s;
722 
723 	DPRINTF(("%s: sc=%p\n", __func__, sc));
724 
725 	s = splir();
726 	/* XXX is this a good check? */
727 	if (events & (POLLOUT | POLLWRNORM))
728 		if (tp->t_outq.c_cc <= tp->t_lowat)
729 			revents |= events & (POLLOUT | POLLWRNORM);
730 
731 	if (events & (POLLIN | POLLRDNORM)) {
732 		if (sc->sc_nframes > 0) {
733 			DPRINTF(("%s: have data\n", __func__));
734 			revents |= events & (POLLIN | POLLRDNORM);
735 		} else {
736 			DPRINTF(("%s: recording select\n", __func__));
737 			selrecord(l, &sc->sc_rsel);
738 		}
739 	}
740 	splx(s);
741 
742 	return (revents);
743 }
744 
745 static void
746 filt_irframetrdetach(struct knote *kn)
747 {
748 	struct tty *tp = kn->kn_hook;
749 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
750 	int s;
751 
752 	s = splir();
753 	SLIST_REMOVE(&sc->sc_rsel.sel_klist, kn, knote, kn_selnext);
754 	splx(s);
755 }
756 
757 static int
758 filt_irframetread(struct knote *kn, long hint)
759 {
760 	struct tty *tp = kn->kn_hook;
761 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
762 
763 	kn->kn_data = sc->sc_nframes;
764 	return (kn->kn_data > 0);
765 }
766 
767 static void
768 filt_irframetwdetach(struct knote *kn)
769 {
770 	struct tty *tp = kn->kn_hook;
771 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
772 	int s;
773 
774 	s = splir();
775 	SLIST_REMOVE(&sc->sc_wsel.sel_klist, kn, knote, kn_selnext);
776 	splx(s);
777 }
778 
779 static int
780 filt_irframetwrite(struct knote *kn, long hint)
781 {
782 	struct tty *tp = kn->kn_hook;
783 
784 	/* XXX double-check this */
785 
786 	if (tp->t_outq.c_cc <= tp->t_lowat) {
787 		kn->kn_data = tp->t_lowat - tp->t_outq.c_cc;
788 		return (1);
789 	}
790 
791 	kn->kn_data = 0;
792 	return (0);
793 }
794 
795 static const struct filterops irframetread_filtops =
796 	{ 1, NULL, filt_irframetrdetach, filt_irframetread };
797 static const struct filterops irframetwrite_filtops =
798 	{ 1, NULL, filt_irframetwdetach, filt_irframetwrite };
799 
800 int
801 irframet_kqfilter(void *h, struct knote *kn)
802 {
803 	struct tty *tp = h;
804 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
805 	struct klist *klist;
806 	int s;
807 
808 	switch (kn->kn_filter) {
809 	case EVFILT_READ:
810 		klist = &sc->sc_rsel.sel_klist;
811 		kn->kn_fop = &irframetread_filtops;
812 		break;
813 	case EVFILT_WRITE:
814 		klist = &sc->sc_wsel.sel_klist;
815 		kn->kn_fop = &irframetwrite_filtops;
816 		break;
817 	default:
818 		return (EINVAL);
819 	}
820 
821 	kn->kn_hook = tp;
822 
823 	s = splir();
824 	SLIST_INSERT_HEAD(klist, kn, kn_selnext);
825 	splx(s);
826 
827 	return (0);
828 }
829 
830 int
831 irframet_set_params(void *h, struct irda_params *p)
832 {
833 	struct tty *tp = h;
834 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
835 	int i;
836 
837 	DPRINTF(("%s: tp=%p speed=%d ebofs=%d maxsize=%d\n",
838 		 __func__, tp, p->speed, p->ebofs, p->maxsize));
839 
840 	if (p->speed != sc->sc_params.speed) {
841 		/* Checked in irframe.c */
842 		mutex_enter(&sc->sc_wr_lk);
843 		irt_dongles[sc->sc_dongle].setspeed(tp, p->speed);
844 		mutex_exit(&sc->sc_wr_lk);
845 		sc->sc_params.speed = p->speed;
846 	}
847 
848 	/* Max size checked in irframe.c */
849 	sc->sc_params.ebofs = p->ebofs;
850 	/* Max size checked in irframe.c */
851 	if (sc->sc_params.maxsize != p->maxsize) {
852 		sc->sc_params.maxsize = p->maxsize;
853 		if (sc->sc_inbuf != NULL)
854 			free(sc->sc_inbuf, M_DEVBUF);
855 		for (i = 0; i < MAXFRAMES; i++)
856 			if (sc->sc_frames[i].buf != NULL)
857 				free(sc->sc_frames[i].buf, M_DEVBUF);
858 		if (sc->sc_params.maxsize != 0) {
859 			sc->sc_inbuf = malloc(sc->sc_params.maxsize+2,
860 					      M_DEVBUF, M_WAITOK);
861 			for (i = 0; i < MAXFRAMES; i++)
862 				sc->sc_frames[i].buf =
863 					malloc(sc->sc_params.maxsize,
864 					       M_DEVBUF, M_WAITOK);
865 		} else {
866 			sc->sc_inbuf = NULL;
867 			for (i = 0; i < MAXFRAMES; i++)
868 				sc->sc_frames[i].buf = NULL;
869 		}
870 	}
871 	sc->sc_framestate = FRAME_OUTSIDE;
872 
873 	return (0);
874 }
875 
876 int
877 irframet_get_speeds(void *h, int *speeds)
878 {
879 	struct tty *tp = h;
880 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
881 
882 	DPRINTF(("%s: tp=%p\n", __func__, tp));
883 
884 	if (sc == NULL)		/* during attach */
885 		*speeds = IRDA_SPEEDS_SIR;
886 	else
887 		*speeds = irt_dongles[sc->sc_dongle].speedmask;
888 	return (0);
889 }
890 
891 int
892 irframet_get_turnarounds(void *h, int *turnarounds)
893 {
894 	struct tty *tp = h;
895 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
896 
897 	DPRINTF(("%s: tp=%p\n", __func__, tp));
898 
899 	*turnarounds = irt_dongles[sc->sc_dongle].turnmask;
900 	return (0);
901 }
902 
903 void
904 irt_ioctl(struct tty *tp, u_long cmd, void *arg)
905 {
906 	const struct cdevsw *cdev;
907 	int error;
908 	dev_t dev;
909 
910 	dev = tp->t_dev;
911 	cdev = cdevsw_lookup(dev);
912 	if (cdev != NULL)
913 		error = (*cdev->d_ioctl)(dev, cmd, arg, 0, curlwp);
914 	else
915 		error = ENXIO;
916 #ifdef DIAGNOSTIC
917 	if (error)
918 		printf("irt_ioctl: cmd=0x%08lx error=%d\n", cmd, error);
919 #endif
920 }
921 
922 void
923 irt_setspeed(struct tty *tp, u_int speed)
924 {
925 	struct termios tt;
926 
927 	irt_ioctl(tp, TIOCGETA,  &tt);
928 	tt.c_ispeed = tt.c_ospeed = speed;
929 	tt.c_cflag &= ~HUPCL;
930 	tt.c_cflag |= CLOCAL;
931 	irt_ioctl(tp, TIOCSETAF, &tt);
932 }
933 
934 void
935 irt_setline(struct tty *tp, u_int line)
936 {
937 	int mline;
938 
939 	irt_ioctl(tp, TIOCMGET, &mline);
940 	mline &= ~(TIOCM_DTR | TIOCM_RTS);
941 	mline |= line;
942 	irt_ioctl(tp, TIOCMSET, (void *)&mline);
943 }
944 
945 void
946 irt_delay(struct tty *tp, u_int ms)
947 {
948 	if (cold)
949 		delay(ms * 1000);
950 	else
951 		tsleep(&irt_delay, PZERO, "irtdly", ms * hz / 1000 + 1);
952 
953 }
954 
955 /**********************************************************************
956  * No dongle
957  **********************************************************************/
958 void
959 irts_none(struct tty *tp, u_int speed)
960 {
961 	irt_setspeed(tp, speed);
962 }
963 
964 /**********************************************************************
965  * Tekram
966  **********************************************************************/
967 #define TEKRAM_PW     0x10
968 
969 #define TEKRAM_115200 (TEKRAM_PW|0x00)
970 #define TEKRAM_57600  (TEKRAM_PW|0x01)
971 #define TEKRAM_38400  (TEKRAM_PW|0x02)
972 #define TEKRAM_19200  (TEKRAM_PW|0x03)
973 #define TEKRAM_9600   (TEKRAM_PW|0x04)
974 #define TEKRAM_2400   (TEKRAM_PW|0x08)
975 
976 #define TEKRAM_TV     (TEKRAM_PW|0x05)
977 
978 void
979 irts_tekram(struct tty *tp, u_int speed)
980 {
981 	int s;
982 
983 	irt_setspeed(tp, 9600);
984 	irt_setline(tp, 0);
985 	irt_delay(tp, 50);
986 
987 	irt_setline(tp, TIOCM_RTS);
988 	irt_delay(tp, 1);
989 
990 	irt_setline(tp, TIOCM_DTR | TIOCM_RTS);
991 	irt_delay(tp, 1);	/* 50 us */
992 
993 	irt_setline(tp, TIOCM_DTR);
994 	irt_delay(tp, 1);	/* 7 us */
995 
996 	switch(speed) {
997 	case 115200: s = TEKRAM_115200; break;
998 	case 57600:  s = TEKRAM_57600; break;
999 	case 38400:  s = TEKRAM_38400; break;
1000 	case 19200:  s = TEKRAM_19200; break;
1001 	case 2400:   s = TEKRAM_2400; break;
1002 	default:     s = TEKRAM_9600; break;
1003 	}
1004 	irt_putc(tp, s);
1005 	irframetstart(tp);
1006 
1007 	irt_delay(tp, 100);
1008 
1009 	irt_setline(tp, TIOCM_DTR | TIOCM_RTS);
1010 	if (speed != 9600)
1011 		irt_setspeed(tp, speed);
1012 	irt_delay(tp, 1);	/* 50 us */
1013 }
1014 
1015 /**********************************************************************
1016  * Jeteye
1017  **********************************************************************/
1018 void
1019 irts_jeteye(struct tty *tp, u_int speed)
1020 {
1021 	switch (speed) {
1022 	case 19200:
1023 		irt_setline(tp, TIOCM_DTR);
1024 		break;
1025 	case 115200:
1026 		irt_setline(tp, TIOCM_DTR | TIOCM_RTS);
1027 		break;
1028 	default: /*9600*/
1029 		irt_setline(tp, TIOCM_RTS);
1030 		break;
1031 	}
1032 	irt_setspeed(tp, speed);
1033 }
1034 
1035 /**********************************************************************
1036  * Actisys
1037  **********************************************************************/
1038 void
1039 irts_actisys(struct tty *tp, u_int speed)
1040 {
1041 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
1042 	int pulses;
1043 
1044 	irt_setspeed(tp, speed);
1045 
1046 	switch(speed) {
1047 	case 19200:  pulses=1; break;
1048 	case 57600:  pulses=2; break;
1049 	case 115200: pulses=3; break;
1050 	case 38400:  pulses=4; break;
1051 	default: /* 9600 */ pulses=0; break;
1052 	}
1053 
1054 	if (sc->sc_dongle_private == 0) {
1055 		sc->sc_dongle_private = 1;
1056 		irt_setline(tp, TIOCM_DTR | TIOCM_RTS);
1057 		/*
1058 		 * Must wait at least 50ms after initial
1059 		 * power on to charge internal capacitor
1060 		 */
1061 		irt_delay(tp, 50);
1062 	}
1063 	irt_setline(tp, TIOCM_RTS);
1064 	delay(2);
1065 	for (;;) {
1066 		irt_setline(tp, TIOCM_DTR | TIOCM_RTS);
1067 		delay(2);
1068 		if (--pulses <= 0)
1069 			break;
1070 		irt_setline(tp, TIOCM_DTR);
1071 		delay(2);
1072 	}
1073 }
1074 
1075 /**********************************************************************
1076  * Litelink
1077  **********************************************************************/
1078 void
1079 irts_litelink(struct tty *tp, u_int speed)
1080 {
1081 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
1082 	int pulses;
1083 
1084 	irt_setspeed(tp, speed);
1085 
1086 	switch(speed) {
1087 	case 57600:  pulses=1; break;
1088 	case 38400:  pulses=2; break;
1089 	case 19200:  pulses=3; break;
1090 	case 9600:   pulses=4; break;
1091 	default: /* 115200 */ pulses=0; break;
1092 	}
1093 
1094 	if (sc->sc_dongle_private == 0) {
1095 		sc->sc_dongle_private = 1;
1096 		irt_setline(tp, TIOCM_DTR | TIOCM_RTS);
1097 	}
1098 	irt_setline(tp, TIOCM_RTS);
1099 	irt_delay(tp, 1); /* 15 us */;
1100 	for (;;) {
1101 		irt_setline(tp, TIOCM_DTR | TIOCM_RTS);
1102 		irt_delay(tp, 1); /* 15 us */;
1103 		if (--pulses <= 0)
1104 			break;
1105 		irt_setline(tp, TIOCM_DTR);
1106 		irt_delay(tp, 1); /* 15 us */;
1107 	}
1108 }
1109 
1110 /**********************************************************************
1111  * Girbil
1112  **********************************************************************/
1113 /* Control register 1 */
1114 #define GIRBIL_TXEN      0x01 /* Enable transmitter */
1115 #define GIRBIL_RXEN      0x02 /* Enable receiver */
1116 #define GIRBIL_ECAN      0x04 /* Cancel self emmited data */
1117 #define GIRBIL_ECHO      0x08 /* Echo control characters */
1118 
1119 /* LED Current Register */
1120 #define GIRBIL_HIGH      0x20
1121 #define GIRBIL_MEDIUM    0x21
1122 #define GIRBIL_LOW       0x22
1123 
1124 /* Baud register */
1125 #define GIRBIL_2400      0x30
1126 #define GIRBIL_4800      0x31
1127 #define GIRBIL_9600      0x32
1128 #define GIRBIL_19200     0x33
1129 #define GIRBIL_38400     0x34
1130 #define GIRBIL_57600     0x35
1131 #define GIRBIL_115200    0x36
1132 
1133 /* Mode register */
1134 #define GIRBIL_IRDA      0x40
1135 #define GIRBIL_ASK       0x41
1136 
1137 /* Control register 2 */
1138 #define GIRBIL_LOAD      0x51 /* Load the new baud rate value */
1139 
1140 void
1141 irts_girbil(struct tty *tp, u_int speed)
1142 {
1143 	int s;
1144 
1145 	irt_setspeed(tp, 9600);
1146 	irt_setline(tp, TIOCM_DTR);
1147 	irt_delay(tp, 5);
1148 	irt_setline(tp, TIOCM_RTS);
1149 	irt_delay(tp, 20);
1150 	switch(speed) {
1151 	case 115200: s = GIRBIL_115200; break;
1152 	case 57600:  s = GIRBIL_57600; break;
1153 	case 38400:  s = GIRBIL_38400; break;
1154 	case 19200:  s = GIRBIL_19200; break;
1155 	case 4800:   s = GIRBIL_4800; break;
1156 	case 2400:   s = GIRBIL_2400; break;
1157 	default:     s = GIRBIL_9600; break;
1158 	}
1159 	irt_putc(tp, GIRBIL_TXEN|GIRBIL_RXEN);
1160 	irt_putc(tp, s);
1161 	irt_putc(tp, GIRBIL_LOAD);
1162 	irframetstart(tp);
1163 	irt_delay(tp, 100);
1164 	irt_setline(tp, TIOCM_DTR | TIOCM_RTS);
1165 	if (speed != 9600)
1166 		irt_setspeed(tp, speed);
1167 }
1168