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