Home | History | Annotate | Line # | Download | only in ir
irframe_tty.c revision 1.2
      1 /*	$NetBSD: irframe_tty.c,v 1.2 2001/12/04 19:56:43 augustss Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2001 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Lennart Augustsson (lennart (at) augustsson.net).
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *        This product includes software developed by the NetBSD
     21  *        Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 /*
     40  * Loosely based on ppp_tty.c.
     41  */
     42 
     43 #include <sys/param.h>
     44 #include <sys/proc.h>
     45 #include <sys/ioctl.h>
     46 #include <sys/tty.h>
     47 #include <sys/kernel.h>
     48 #include <sys/malloc.h>
     49 #include <sys/conf.h>
     50 #include <sys/systm.h>
     51 #include <sys/device.h>
     52 #include <sys/file.h>
     53 #include <sys/vnode.h>
     54 #include <sys/poll.h>
     55 
     56 #include <dev/ir/ir.h>
     57 #include <dev/ir/irdaio.h>
     58 #include <dev/ir/irframevar.h>
     59 
     60 /* Macros to clear/set/test flags. */
     61 #define	SET(t, f)	(t) |= (f)
     62 #define	CLR(t, f)	(t) &= ~(f)
     63 #define	ISSET(t, f)	((t) & (f))
     64 
     65 #ifdef IRFRAMET_DEBUG
     66 #define DPRINTF(x)	if (irframetdebug) printf x
     67 #define Static
     68 int irframetdebug = 1;
     69 #else
     70 #define DPRINTF(x)
     71 #define Static static
     72 #endif
     73 
     74 /* Protocol constants */
     75 #define SIR_EXTRA_BOF            0xff
     76 #define SIR_BOF                  0xc0
     77 #define SIR_CE                   0x7d
     78 #define SIR_EOF                  0xc1
     79 
     80 #define SIR_ESC_BIT              0x20
     81 /*****/
     82 
     83 #define MAX_IRDA_FRAME 5000	/* XXX what is it? */
     84 
     85 struct frame {
     86 	u_char *buf;
     87 	u_int len;
     88 };
     89 #define MAXFRAMES 4
     90 
     91 struct irframet_softc {
     92 	struct irframe_softc sc_irp;
     93 	struct tty *sc_tp;
     94 
     95 	int sc_state;
     96 #define	IRT_RSLP		0x01	/* waiting for data (read) */
     97 #if 0
     98 #define	IRT_WSLP		0x02	/* waiting for data (write) */
     99 #define IRT_CLOSING		0x04	/* waiting for output to drain */
    100 #endif
    101 
    102 	int sc_ebofs;
    103 
    104 	u_char* sc_inbuf;
    105 	int sc_maxsize;
    106 	int sc_framestate;
    107 #define FRAME_OUTSIDE    0
    108 #define FRAME_INSIDE     1
    109 #define FRAME_ESCAPE     2
    110 	int sc_inchars;
    111 	int sc_inFCS;
    112 	struct callout sc_timeout;
    113 
    114 	u_int sc_nframes;
    115 	u_int sc_framei;
    116 	u_int sc_frameo;
    117 	struct frame sc_frames[MAXFRAMES];
    118 	struct selinfo sc_rsel;
    119 };
    120 
    121 /* line discipline methods */
    122 int	irframetopen(dev_t dev, struct tty *tp);
    123 int	irframetclose(struct tty *tp, int flag);
    124 int	irframetioctl(struct tty *tp, u_long cmd, caddr_t data, int flag,
    125 		     struct proc *);
    126 int	irframetinput(int c, struct tty *tp);
    127 int	irframetstart(struct tty *tp);
    128 
    129 /* pseudo device init */
    130 void	irframettyattach(int);
    131 
    132 /* irframe methods */
    133 Static int	irframet_open(void *h, int flag, int mode, struct proc *p);
    134 Static int	irframet_close(void *h, int flag, int mode, struct proc *p);
    135 Static int	irframet_read(void *h, struct uio *uio, int flag);
    136 Static int	irframet_write(void *h, struct uio *uio, int flag);
    137 Static int	irframet_poll(void *h, int events, struct proc *p);
    138 Static int	irframet_set_params(void *h, struct irda_params *params);
    139 Static int	irframet_get_speeds(void *h, int *speeds);
    140 Static int	irframet_get_turnarounds(void *h, int *times);
    141 
    142 /* internal */
    143 Static int	irt_write_buf(void *h, void *buf, size_t len);
    144 Static int	irt_putc(int c, struct tty *tp);
    145 Static int	irt_putesc(int c, struct tty *tp);
    146 Static void	irt_frame(struct irframet_softc *sc, u_char *buf, u_int len);
    147 Static void	irt_timeout(void *v);
    148 
    149 Static struct irframe_methods irframet_methods = {
    150 	irframet_open, irframet_close, irframet_read, irframet_write,
    151 	irframet_poll, irframet_set_params,
    152 	irframet_get_speeds, irframet_get_turnarounds
    153 };
    154 
    155 void
    156 irframettyattach(int n)
    157 {
    158 }
    159 
    160 /*
    161  * CRC
    162  */
    163 
    164 static const u_int16_t fcstab[] = {
    165   0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
    166   0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
    167   0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
    168   0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
    169   0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
    170   0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
    171   0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
    172   0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
    173   0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
    174   0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
    175   0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
    176   0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
    177   0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
    178   0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
    179   0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
    180   0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
    181   0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
    182   0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
    183   0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
    184   0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
    185   0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
    186   0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
    187   0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
    188   0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
    189   0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
    190   0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
    191   0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
    192   0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
    193   0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
    194   0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
    195   0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
    196   0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
    197 };
    198 
    199 static const u_int16_t INITFCS = 0xffff;
    200 static const u_int16_t GOODFCS = 0xf0b8;
    201 
    202 static __inline u_int16_t updateFCS(u_int16_t fcs, int c) {
    203 	return (fcs >> 8) ^ fcstab[(fcs^c) & 0xff];
    204 }
    205 
    206 
    207 /*
    208  * Line specific open routine for async tty devices.
    209  * Attach the given tty to the first available irframe unit.
    210  * Called from device open routine or ttioctl.
    211  */
    212 /* ARGSUSED */
    213 int
    214 irframetopen(dev_t dev, struct tty *tp)
    215 {
    216 	struct proc *p = curproc;		/* XXX */
    217 	struct irframet_softc *sc;
    218 	int error, s;
    219 
    220 	DPRINTF(("%s\n", __FUNCTION__));
    221 
    222 	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
    223 		return (error);
    224 
    225 	s = spltty();
    226 
    227 	DPRINTF(("%s: linesw=%p disc=%d\n", __FUNCTION__, tp->t_linesw,
    228 		 tp->t_linesw->l_no));
    229 	if (tp->t_linesw->l_no == IRFRAMEDISC) {
    230 		sc = (struct irframet_softc *)tp->t_sc;
    231 		DPRINTF(("%s: sc=%p sc_tp=%p\n", __FUNCTION__, sc, sc->sc_tp));
    232 		if (sc != NULL) {
    233 			splx(s);
    234 			return (EBUSY);
    235 		}
    236 	}
    237 
    238 	printf("%s attached at tty%02d:", sc->sc_irp.sc_dev.dv_xname,
    239 	    minor(tp->t_dev));
    240 	tp->t_sc = irframe_alloc(sizeof (struct irframet_softc),
    241 			&irframet_methods, tp);
    242 	sc = (struct irframet_softc *)tp->t_sc;
    243 	sc->sc_tp = tp;
    244 
    245 	DPRINTF(("%s: set sc=%p\n", __FUNCTION__, sc));
    246 
    247 	ttyflush(tp, FREAD | FWRITE);
    248 
    249 	splx(s);
    250 
    251 	sc->sc_ebofs = IRDA_DEFAULT_EBOFS;
    252 	sc->sc_maxsize = 0;
    253 	sc->sc_framestate = FRAME_OUTSIDE;
    254 	sc->sc_nframes = 0;
    255 	sc->sc_framei = 0;
    256 	sc->sc_frameo = 0;
    257 	callout_init(&sc->sc_timeout);
    258 
    259 	return (0);
    260 }
    261 
    262 /*
    263  * Line specific close routine, called from device close routine
    264  * and from ttioctl.
    265  * Detach the tty from the irframe unit.
    266  * Mimics part of ttyclose().
    267  */
    268 int
    269 irframetclose(struct tty *tp, int flag)
    270 {
    271 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    272 	int s;
    273 	int i;
    274 
    275 	DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
    276 
    277 	callout_stop(&sc->sc_timeout);
    278 	s = splir();
    279 	if (sc->sc_inbuf != NULL) {
    280 		free(sc->sc_inbuf, M_DEVBUF);
    281 		sc->sc_inbuf = NULL;
    282 	}
    283 	for (i = 0; i < MAXFRAMES; i++) {
    284 		if (sc->sc_frames[i].buf != NULL) {
    285 			free(sc->sc_frames[i].buf, M_DEVBUF);
    286 			sc->sc_frames[i].buf = NULL;
    287 		}
    288 	}
    289 	splx(s);
    290 
    291 	s = spltty();
    292 	ttyflush(tp, FREAD | FWRITE);
    293 	tp->t_linesw = linesw[0]; /* default line discipline */
    294 	if (sc != NULL) {
    295 		tp->t_sc = NULL;
    296 		printf("%s detached from tty%02d\n", sc->sc_irp.sc_dev.dv_xname,
    297 		    minor(tp->t_dev));
    298 
    299 		if (sc->sc_tp == tp)
    300 			irframe_dealloc(&sc->sc_irp.sc_dev);
    301 	}
    302 	splx(s);
    303 	return (0);
    304 }
    305 
    306 /*
    307  * Line specific (tty) ioctl routine.
    308  * This discipline requires that tty device drivers call
    309  * the line specific l_ioctl routine from their ioctl routines.
    310  */
    311 /* ARGSUSED */
    312 int
    313 irframetioctl(struct tty *tp, u_long cmd, caddr_t data, int flag,
    314 	     struct proc *p)
    315 {
    316 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    317 	int error;
    318 
    319 	DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
    320 
    321 	if (sc == NULL || tp != sc->sc_tp)
    322 		return (-1);
    323 
    324 	error = 0;
    325 	switch (cmd) {
    326 	default:
    327 #if 0
    328 		error = irframeioctl(sc, cmd, data, flag, p);
    329 #else
    330 		error = EINVAL;
    331 #endif
    332 		break;
    333 	}
    334 
    335 	return (error);
    336 }
    337 
    338 /*
    339  * Start output on async tty interface.  If the transmit queue
    340  * has drained sufficiently, arrange for irframeasyncstart to be
    341  * called later at splsoftnet.
    342  * Called at spltty or higher.
    343  */
    344 int
    345 irframetstart(struct tty *tp)
    346 {
    347 	/*struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;*/
    348 
    349 	DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
    350 
    351 	/*
    352 	 * If there is stuff in the output queue, send it now.
    353 	 * We are being called in lieu of ttstart and must do what it would.
    354 	 */
    355 	if (tp->t_oproc != NULL)
    356 		(*tp->t_oproc)(tp);
    357 
    358 	return (0);
    359 }
    360 
    361 void
    362 irt_frame(struct irframet_softc *sc, u_char *buf, u_int len)
    363 {
    364 	if (sc->sc_nframes >= MAXFRAMES) {
    365 #ifdef IRFRAMET_DEBUG
    366 		printf("%s: dropped frame\n", __FUNCTION__);
    367 #endif
    368 		return;
    369 	}
    370 	if (sc->sc_frames[sc->sc_framei].buf == NULL)
    371 		return;
    372 	memcpy(sc->sc_frames[sc->sc_framei].buf, buf, len);
    373 	sc->sc_frames[sc->sc_framei].len = len;
    374 	sc->sc_framei = (sc->sc_framei+1) % MAXFRAMES;
    375 	sc->sc_nframes++;
    376 	if (sc->sc_state & IRT_RSLP) {
    377 		sc->sc_state &= ~IRT_RSLP;
    378 		DPRINTF(("%s: waking up reader\n", __FUNCTION__));
    379 		wakeup(sc->sc_frames);
    380 	}
    381 	selwakeup(&sc->sc_rsel);
    382 }
    383 
    384 void
    385 irt_timeout(void *v)
    386 {
    387 	struct irframet_softc *sc = v;
    388 
    389 #ifdef IRFRAMET_DEBUG
    390 	if (sc->sc_framestate != FRAME_OUTSIDE)
    391 		printf("%s: input frame timeout\n", __FUNCTION__);
    392 #endif
    393 	sc->sc_framestate = FRAME_OUTSIDE;
    394 }
    395 
    396 int
    397 irframetinput(int c, struct tty *tp)
    398 {
    399 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    400 
    401 	DPRINTF(("%s: tp=%p c=0x%0x\n", __FUNCTION__, tp, c));
    402 
    403 	if (sc == NULL || tp != (struct tty *)sc->sc_tp)
    404 		return (0);
    405 
    406 	if (sc->sc_inbuf == NULL)
    407 		return (0);
    408 
    409 	switch (c) {
    410 	case SIR_BOF:
    411 		sc->sc_framestate = FRAME_INSIDE;
    412 		sc->sc_inchars = 0;
    413 		sc->sc_inFCS = INITFCS;
    414 		break;
    415 	case SIR_EOF:
    416 		if (sc->sc_framestate == FRAME_INSIDE &&
    417 		    sc->sc_inchars >= 4 && sc->sc_inFCS == GOODFCS) {
    418 			irt_frame(sc, sc->sc_inbuf, sc->sc_inchars - 2);
    419 		} else if (sc->sc_framestate != FRAME_OUTSIDE) {
    420 #ifdef IRFRAMET_DEBUG
    421 			printf("%s: malformed input frame\n", __FUNCTION__);
    422 #endif
    423 		}
    424 		sc->sc_framestate = FRAME_OUTSIDE;
    425 		break;
    426 	case SIR_CE:
    427 		if (sc->sc_framestate == FRAME_INSIDE)
    428 			sc->sc_framestate = FRAME_ESCAPE;
    429 		break;
    430 	default:
    431 		if (sc->sc_framestate != FRAME_OUTSIDE) {
    432 			if (sc->sc_framestate == FRAME_ESCAPE) {
    433 				sc->sc_framestate = FRAME_INSIDE;
    434 				c ^= SIR_ESC_BIT;
    435 			}
    436 			if (sc->sc_inchars < sc->sc_maxsize + 2) {
    437 				sc->sc_inbuf[sc->sc_inchars++] = c;
    438 				sc->sc_inFCS = updateFCS(sc->sc_inFCS, c);
    439 			} else {
    440 				sc->sc_framestate = FRAME_OUTSIDE;
    441 #ifdef IRFRAMET_DEBUG
    442 				printf("%s: input frame overrun\n",
    443 				       __FUNCTION__);
    444 #endif
    445 			}
    446 		}
    447 		break;
    448 	}
    449 
    450 	if (sc->sc_framestate != FRAME_OUTSIDE) {
    451 		callout_reset(&sc->sc_timeout, hz/100, irt_timeout, sc);
    452 	}
    453 
    454 	return (0);
    455 }
    456 
    457 
    458 /*** irframe methods ***/
    459 
    460 int
    461 irframet_open(void *h, int flag, int mode, struct proc *p)
    462 {
    463 	struct tty *tp = h;
    464 
    465 	tp = tp;
    466 	DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
    467 	return (0);
    468 }
    469 
    470 int
    471 irframet_close(void *h, int flag, int mode, struct proc *p)
    472 {
    473 	struct tty *tp = h;
    474 
    475 	tp = tp;
    476 	DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
    477 	return (0);
    478 }
    479 
    480 int
    481 irframet_read(void *h, struct uio *uio, int flag)
    482 {
    483 	struct tty *tp = h;
    484 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    485 	int error = 0;
    486 	int s;
    487 
    488 	DPRINTF(("%s: resid=%d, iovcnt=%d, offset=%ld\n",
    489 		 __FUNCTION__, uio->uio_resid, uio->uio_iovcnt,
    490 		 (long)uio->uio_offset));
    491 
    492 	s = splir();
    493 	while (sc->sc_nframes == 0) {
    494 		if (flag & IO_NDELAY) {
    495 			splx(s);
    496 			return (EWOULDBLOCK);
    497 		}
    498 		sc->sc_state |= IRT_RSLP;
    499 		DPRINTF(("%s: sleep\n", __FUNCTION__));
    500 		error = tsleep(sc->sc_frames, PZERO | PCATCH, "irtrd", 0);
    501 		DPRINTF(("%s: woke, error=%d\n", __FUNCTION__, error));
    502 		if (error) {
    503 			sc->sc_state &= ~IRT_RSLP;
    504 			break;
    505 		}
    506 	}
    507 
    508 	/* Do just one frame transfer per read */
    509 	if (!error) {
    510 		if (uio->uio_resid < sc->sc_frames[sc->sc_frameo].len) {
    511 			DPRINTF(("%s: uio buffer smaller than frame size (%d < %d)\n", __FUNCTION__, uio->uio_resid, sc->sc_frames[sc->sc_frameo].len));
    512 			error = EINVAL;
    513 		} else {
    514 			DPRINTF(("%s: moving %d bytes\n", __FUNCTION__,
    515 				 sc->sc_frames[sc->sc_frameo].len));
    516 				error = uiomove(sc->sc_frames[sc->sc_frameo].buf,
    517 					sc->sc_frames[sc->sc_frameo].len, uio);
    518 		}
    519 		sc->sc_frameo++;
    520 		sc->sc_nframes--;
    521 	}
    522 	splx(s);
    523 
    524 	return (error);
    525 }
    526 
    527 int
    528 irt_putc(int c, struct tty *tp)
    529 {
    530 	int s;
    531 	int error;
    532 
    533 	if (tp->t_outq.c_cc > tp->t_hiwat) {
    534 		irframetstart(tp);
    535 		s = spltty();
    536 		/*
    537 		 * This can only occur if FLUSHO is set in t_lflag,
    538 		 * or if ttstart/oproc is synchronous (or very fast).
    539 		 */
    540 		if (tp->t_outq.c_cc <= tp->t_hiwat) {
    541 			splx(s);
    542 			goto go;
    543 		}
    544 		SET(tp->t_state, TS_ASLEEP);
    545 		error = ttysleep(tp, &tp->t_outq, TTOPRI | PCATCH, ttyout, 0);
    546 		splx(s);
    547 		if (error)
    548 			return (error);
    549 	}
    550  go:
    551 	if (putc(c, &tp->t_rawq) < 0) {
    552 		printf("irframe: putc failed\n");
    553 		return (EIO);
    554 	}
    555 	return (0);
    556 }
    557 
    558 int
    559 irt_putesc(int c, struct tty *tp)
    560 {
    561 	int error;
    562 
    563 	if (c == SIR_BOF || c == SIR_EOF || c == SIR_CE) {
    564 		error = irt_putc(SIR_CE, tp);
    565 		if (!error)
    566 			error = irt_putc(SIR_ESC_BIT^c, tp);
    567 	} else {
    568 		error = irt_putc(c, tp);
    569 	}
    570 	return (error);
    571 }
    572 
    573 int
    574 irframet_write(void *h, struct uio *uio, int flag)
    575 {
    576 	u_int8_t buf[MAX_IRDA_FRAME];
    577 	size_t n;
    578 	int error;
    579 
    580 	DPRINTF(("%s\n", __FUNCTION__));
    581 
    582 	n = uio->uio_resid;
    583 	if (n > MAX_IRDA_FRAME)
    584 		return (EINVAL);
    585 	error = uiomove(buf, n, uio);
    586 	if (error)
    587 		return (error);
    588 	return (irt_write_buf(h, buf, n));
    589 }
    590 
    591 int
    592 irt_write_buf(void *h, void *buf, size_t len)
    593 {
    594 	struct tty *tp = h;
    595 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    596 	u_int8_t *cp = buf;
    597 	int c, error, ofcs, i;
    598 
    599 	DPRINTF(("%s: tp=%p len=%d\n", __FUNCTION__, tp, len));
    600 
    601 	ofcs = INITFCS;
    602 	error = 0;
    603 
    604 	for (i = 0; i < sc->sc_ebofs; i++)
    605 		irt_putc(SIR_EXTRA_BOF, tp);
    606 	irt_putc(SIR_BOF, tp);
    607 
    608 	while (len-- > 0) {
    609 		c = *cp++;
    610 		ofcs = updateFCS(ofcs, c);
    611 		error = irt_putesc(c, tp);
    612 		if (error)
    613 			return (error);
    614 	}
    615 
    616 	ofcs = ~ofcs;
    617 	error = irt_putesc(ofcs & 0xff, tp);
    618 	if (!error)
    619 		error = irt_putesc((ofcs >> 8) & 0xff, tp);
    620 	if (!error)
    621 		error = irt_putc(SIR_EOF, tp);
    622 
    623 	irframetstart(tp);
    624 
    625 	return (error);
    626 }
    627 
    628 int
    629 irframet_poll(void *h, int events, struct proc *p)
    630 {
    631 	struct tty *tp = h;
    632 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    633 	int revents = 0;
    634 	int s;
    635 
    636 	DPRINTF(("%s: sc=%p\n", __FUNCTION__, sc));
    637 
    638 	s = splir();
    639 	if (events & (POLLOUT | POLLWRNORM))
    640 		revents |= events & (POLLOUT | POLLWRNORM);
    641 	if (events & (POLLIN | POLLRDNORM)) {
    642 		if (sc->sc_nframes > 0) {
    643 			DPRINTF(("%s: have data\n", __FUNCTION__));
    644 			revents |= events & (POLLIN | POLLRDNORM);
    645 		} else {
    646 			DPRINTF(("%s: recording select", __FUNCTION__));
    647 			selrecord(p, &sc->sc_rsel);
    648 		}
    649 	}
    650 	splx(s);
    651 
    652 	return (revents);
    653 }
    654 
    655 int
    656 irframet_set_params(void *h, struct irda_params *p)
    657 {
    658 	struct tty *tp = h;
    659 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    660 	int i;
    661 
    662 	DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
    663 
    664 	/* XXX speed */
    665 	sc->sc_ebofs = p->ebofs;
    666 	if (sc->sc_maxsize != p->maxsize) {
    667 		sc->sc_maxsize = p->maxsize;
    668 		if (sc->sc_inbuf != NULL)
    669 			free(sc->sc_inbuf, M_DEVBUF);
    670 		for (i = 0; i < MAXFRAMES; i++)
    671 			if (sc->sc_frames[i].buf != NULL)
    672 				free(sc->sc_frames[i].buf, M_DEVBUF);
    673 		if (sc->sc_maxsize != 0) {
    674 			sc->sc_inbuf = malloc(sc->sc_maxsize+2, M_DEVBUF,
    675 					      M_WAITOK);
    676 			for (i = 0; i < MAXFRAMES; i++)
    677 				sc->sc_frames[i].buf = malloc(sc->sc_maxsize,
    678 							   M_DEVBUF, M_WAITOK);
    679 		} else {
    680 			sc->sc_inbuf = NULL;
    681 			for (i = 0; i < MAXFRAMES; i++)
    682 				sc->sc_frames[i].buf = NULL;
    683 		}
    684 	}
    685 	sc->sc_framestate = FRAME_OUTSIDE;
    686 
    687 	return (0);
    688 }
    689 
    690 int
    691 irframet_get_speeds(void *h, int *speeds)
    692 {
    693 	struct tty *tp = h;
    694 
    695 	tp = tp;
    696 	DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
    697 	*speeds = IRDA_SPEEDS_SIR;
    698 	return (0);
    699 }
    700 
    701 int
    702 irframet_get_turnarounds(void *h, int *turnarounds)
    703 {
    704 	struct tty *tp = h;
    705 
    706 	tp = tp;
    707 	DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
    708 	*turnarounds = IRDA_TURNT_10000;
    709 	return (0);
    710 }
    711