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