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