Home | History | Annotate | Line # | Download | only in ir
irframe_tty.c revision 1.4
      1 /*	$NetBSD: irframe_tty.c,v 1.4 2001/12/04 21:50:50 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 	int sc_speed;
    104 
    105 	u_char* sc_inbuf;
    106 	int sc_maxsize;
    107 	int sc_framestate;
    108 #define FRAME_OUTSIDE    0
    109 #define FRAME_INSIDE     1
    110 #define FRAME_ESCAPE     2
    111 	int sc_inchars;
    112 	int sc_inFCS;
    113 	struct callout sc_timeout;
    114 
    115 	u_int sc_nframes;
    116 	u_int sc_framei;
    117 	u_int sc_frameo;
    118 	struct frame sc_frames[MAXFRAMES];
    119 	struct selinfo sc_rsel;
    120 };
    121 
    122 /* line discipline methods */
    123 int	irframetopen(dev_t dev, struct tty *tp);
    124 int	irframetclose(struct tty *tp, int flag);
    125 int	irframetioctl(struct tty *tp, u_long cmd, caddr_t data, int flag,
    126 		     struct proc *);
    127 int	irframetinput(int c, struct tty *tp);
    128 int	irframetstart(struct tty *tp);
    129 
    130 /* pseudo device init */
    131 void	irframettyattach(int);
    132 
    133 /* irframe methods */
    134 Static int	irframet_open(void *h, int flag, int mode, struct proc *p);
    135 Static int	irframet_close(void *h, int flag, int mode, struct proc *p);
    136 Static int	irframet_read(void *h, struct uio *uio, int flag);
    137 Static int	irframet_write(void *h, struct uio *uio, int flag);
    138 Static int	irframet_poll(void *h, int events, struct proc *p);
    139 Static int	irframet_set_params(void *h, struct irda_params *params);
    140 Static int	irframet_get_speeds(void *h, int *speeds);
    141 Static int	irframet_get_turnarounds(void *h, int *times);
    142 
    143 /* internal */
    144 Static int	irt_write_buf(void *h, void *buf, size_t len);
    145 Static int	irt_putc(int c, struct tty *tp);
    146 Static int	irt_putesc(int c, struct tty *tp);
    147 Static void	irt_frame(struct irframet_softc *sc, u_char *buf, u_int len);
    148 Static void	irt_timeout(void *v);
    149 
    150 Static struct irframe_methods irframet_methods = {
    151 	irframet_open, irframet_close, irframet_read, irframet_write,
    152 	irframet_poll, irframet_set_params,
    153 	irframet_get_speeds, irframet_get_turnarounds
    154 };
    155 
    156 void
    157 irframettyattach(int n)
    158 {
    159 }
    160 
    161 /*
    162  * CRC
    163  */
    164 
    165 static const u_int16_t fcstab[] = {
    166   0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
    167   0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
    168   0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
    169   0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
    170   0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
    171   0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
    172   0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
    173   0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
    174   0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
    175   0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
    176   0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
    177   0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
    178   0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
    179   0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
    180   0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
    181   0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
    182   0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
    183   0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
    184   0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
    185   0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
    186   0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
    187   0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
    188   0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
    189   0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
    190   0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
    191   0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
    192   0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
    193   0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
    194   0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
    195   0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
    196   0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
    197   0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
    198 };
    199 
    200 static const u_int16_t INITFCS = 0xffff;
    201 static const u_int16_t GOODFCS = 0xf0b8;
    202 
    203 static __inline u_int16_t updateFCS(u_int16_t fcs, int c) {
    204 	return (fcs >> 8) ^ fcstab[(fcs^c) & 0xff];
    205 }
    206 
    207 
    208 /*
    209  * Line specific open routine for async tty devices.
    210  * Attach the given tty to the first available irframe unit.
    211  * Called from device open routine or ttioctl.
    212  */
    213 /* ARGSUSED */
    214 int
    215 irframetopen(dev_t dev, struct tty *tp)
    216 {
    217 	struct proc *p = curproc;		/* XXX */
    218 	struct irframet_softc *sc;
    219 	int error, s;
    220 
    221 	DPRINTF(("%s\n", __FUNCTION__));
    222 
    223 	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
    224 		return (error);
    225 
    226 	s = spltty();
    227 
    228 	DPRINTF(("%s: linesw=%p disc=%d\n", __FUNCTION__, tp->t_linesw,
    229 		 tp->t_linesw->l_no));
    230 	if (tp->t_linesw->l_no == IRFRAMEDISC) {
    231 		sc = (struct irframet_softc *)tp->t_sc;
    232 		DPRINTF(("%s: sc=%p sc_tp=%p\n", __FUNCTION__, sc, sc->sc_tp));
    233 		if (sc != NULL) {
    234 			splx(s);
    235 			return (EBUSY);
    236 		}
    237 	}
    238 
    239 	printf("%s attached at tty%02d:", sc->sc_irp.sc_dev.dv_xname,
    240 	    minor(tp->t_dev));
    241 	tp->t_sc = irframe_alloc(sizeof (struct irframet_softc),
    242 			&irframet_methods, tp);
    243 	sc = (struct irframet_softc *)tp->t_sc;
    244 	sc->sc_tp = tp;
    245 
    246 	DPRINTF(("%s: set sc=%p\n", __FUNCTION__, sc));
    247 
    248 	ttyflush(tp, FREAD | FWRITE);
    249 
    250 	splx(s);
    251 
    252 	return (0);
    253 }
    254 
    255 /*
    256  * Line specific close routine, called from device close routine
    257  * and from ttioctl.
    258  * Detach the tty from the irframe unit.
    259  * Mimics part of ttyclose().
    260  */
    261 int
    262 irframetclose(struct tty *tp, int flag)
    263 {
    264 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    265 	int s;
    266 
    267 	DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
    268 
    269 	s = spltty();
    270 	ttyflush(tp, FREAD | FWRITE);
    271 	tp->t_linesw = linesw[0]; /* default line discipline */
    272 	if (sc != NULL) {
    273 		tp->t_sc = NULL;
    274 		printf("%s detached from tty%02d\n", sc->sc_irp.sc_dev.dv_xname,
    275 		    minor(tp->t_dev));
    276 
    277 		if (sc->sc_tp == tp)
    278 			irframe_dealloc(&sc->sc_irp.sc_dev);
    279 	}
    280 	splx(s);
    281 	return (0);
    282 }
    283 
    284 /*
    285  * Line specific (tty) ioctl routine.
    286  * This discipline requires that tty device drivers call
    287  * the line specific l_ioctl routine from their ioctl routines.
    288  */
    289 /* ARGSUSED */
    290 int
    291 irframetioctl(struct tty *tp, u_long cmd, caddr_t data, int flag,
    292 	     struct proc *p)
    293 {
    294 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    295 	int error;
    296 
    297 	DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
    298 
    299 	if (sc == NULL || tp != sc->sc_tp)
    300 		return (-1);
    301 
    302 	error = 0;
    303 	switch (cmd) {
    304 	default:
    305 #if 0
    306 		error = irframeioctl(sc, cmd, data, flag, p);
    307 #else
    308 		error = EINVAL;
    309 #endif
    310 		break;
    311 	}
    312 
    313 	return (error);
    314 }
    315 
    316 /*
    317  * Start output on async tty interface.  If the transmit queue
    318  * has drained sufficiently, arrange for irframeasyncstart to be
    319  * called later at splsoftnet.
    320  * Called at spltty or higher.
    321  */
    322 int
    323 irframetstart(struct tty *tp)
    324 {
    325 	/*struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;*/
    326 
    327 	DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
    328 
    329 	/*
    330 	 * If there is stuff in the output queue, send it now.
    331 	 * We are being called in lieu of ttstart and must do what it would.
    332 	 */
    333 	if (tp->t_oproc != NULL)
    334 		(*tp->t_oproc)(tp);
    335 
    336 	return (0);
    337 }
    338 
    339 void
    340 irt_frame(struct irframet_softc *sc, u_char *buf, u_int len)
    341 {
    342 	if (sc->sc_nframes >= MAXFRAMES) {
    343 #ifdef IRFRAMET_DEBUG
    344 		printf("%s: dropped frame\n", __FUNCTION__);
    345 #endif
    346 		return;
    347 	}
    348 	if (sc->sc_frames[sc->sc_framei].buf == NULL)
    349 		return;
    350 	memcpy(sc->sc_frames[sc->sc_framei].buf, buf, len);
    351 	sc->sc_frames[sc->sc_framei].len = len;
    352 	sc->sc_framei = (sc->sc_framei+1) % MAXFRAMES;
    353 	sc->sc_nframes++;
    354 	if (sc->sc_state & IRT_RSLP) {
    355 		sc->sc_state &= ~IRT_RSLP;
    356 		DPRINTF(("%s: waking up reader\n", __FUNCTION__));
    357 		wakeup(sc->sc_frames);
    358 	}
    359 	selwakeup(&sc->sc_rsel);
    360 }
    361 
    362 void
    363 irt_timeout(void *v)
    364 {
    365 	struct irframet_softc *sc = v;
    366 
    367 #ifdef IRFRAMET_DEBUG
    368 	if (sc->sc_framestate != FRAME_OUTSIDE)
    369 		printf("%s: input frame timeout\n", __FUNCTION__);
    370 #endif
    371 	sc->sc_framestate = FRAME_OUTSIDE;
    372 }
    373 
    374 int
    375 irframetinput(int c, struct tty *tp)
    376 {
    377 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    378 
    379 	DPRINTF(("%s: tp=%p c=0x%0x\n", __FUNCTION__, tp, c));
    380 
    381 	if (sc == NULL || tp != (struct tty *)sc->sc_tp)
    382 		return (0);
    383 
    384 	if (sc->sc_inbuf == NULL)
    385 		return (0);
    386 
    387 	switch (c) {
    388 	case SIR_BOF:
    389 		sc->sc_framestate = FRAME_INSIDE;
    390 		sc->sc_inchars = 0;
    391 		sc->sc_inFCS = INITFCS;
    392 		break;
    393 	case SIR_EOF:
    394 		if (sc->sc_framestate == FRAME_INSIDE &&
    395 		    sc->sc_inchars >= 4 && sc->sc_inFCS == GOODFCS) {
    396 			irt_frame(sc, sc->sc_inbuf, sc->sc_inchars - 2);
    397 		} else if (sc->sc_framestate != FRAME_OUTSIDE) {
    398 #ifdef IRFRAMET_DEBUG
    399 			printf("%s: malformed input frame\n", __FUNCTION__);
    400 #endif
    401 		}
    402 		sc->sc_framestate = FRAME_OUTSIDE;
    403 		break;
    404 	case SIR_CE:
    405 		if (sc->sc_framestate == FRAME_INSIDE)
    406 			sc->sc_framestate = FRAME_ESCAPE;
    407 		break;
    408 	default:
    409 		if (sc->sc_framestate != FRAME_OUTSIDE) {
    410 			if (sc->sc_framestate == FRAME_ESCAPE) {
    411 				sc->sc_framestate = FRAME_INSIDE;
    412 				c ^= SIR_ESC_BIT;
    413 			}
    414 			if (sc->sc_inchars < sc->sc_maxsize + 2) {
    415 				sc->sc_inbuf[sc->sc_inchars++] = c;
    416 				sc->sc_inFCS = updateFCS(sc->sc_inFCS, c);
    417 			} else {
    418 				sc->sc_framestate = FRAME_OUTSIDE;
    419 #ifdef IRFRAMET_DEBUG
    420 				printf("%s: input frame overrun\n",
    421 				       __FUNCTION__);
    422 #endif
    423 			}
    424 		}
    425 		break;
    426 	}
    427 
    428 	if (sc->sc_framestate != FRAME_OUTSIDE) {
    429 		callout_reset(&sc->sc_timeout, hz/100, irt_timeout, sc);
    430 	}
    431 
    432 	return (0);
    433 }
    434 
    435 
    436 /*** irframe methods ***/
    437 
    438 int
    439 irframet_open(void *h, int flag, int mode, struct proc *p)
    440 {
    441 	struct tty *tp = h;
    442 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    443 
    444 	DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
    445 
    446 	sc->sc_speed = 0;
    447 	sc->sc_ebofs = IRDA_DEFAULT_EBOFS;
    448 	sc->sc_maxsize = 0;
    449 	sc->sc_framestate = FRAME_OUTSIDE;
    450 	sc->sc_nframes = 0;
    451 	sc->sc_framei = 0;
    452 	sc->sc_frameo = 0;
    453 	callout_init(&sc->sc_timeout);
    454 
    455 	return (0);
    456 }
    457 
    458 int
    459 irframet_close(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 	int i, s;
    464 
    465 	DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
    466 
    467 	callout_stop(&sc->sc_timeout);
    468 	s = splir();
    469 	if (sc->sc_inbuf != NULL) {
    470 		free(sc->sc_inbuf, M_DEVBUF);
    471 		sc->sc_inbuf = NULL;
    472 	}
    473 	for (i = 0; i < MAXFRAMES; i++) {
    474 		if (sc->sc_frames[i].buf != NULL) {
    475 			free(sc->sc_frames[i].buf, M_DEVBUF);
    476 			sc->sc_frames[i].buf = NULL;
    477 		}
    478 	}
    479 	splx(s);
    480 
    481 	return (0);
    482 }
    483 
    484 int
    485 irframet_read(void *h, struct uio *uio, int flag)
    486 {
    487 	struct tty *tp = h;
    488 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    489 	int error = 0;
    490 	int s;
    491 
    492 	DPRINTF(("%s: resid=%d, iovcnt=%d, offset=%ld\n",
    493 		 __FUNCTION__, uio->uio_resid, uio->uio_iovcnt,
    494 		 (long)uio->uio_offset));
    495 
    496 	s = splir();
    497 	while (sc->sc_nframes == 0) {
    498 		if (flag & IO_NDELAY) {
    499 			splx(s);
    500 			return (EWOULDBLOCK);
    501 		}
    502 		sc->sc_state |= IRT_RSLP;
    503 		DPRINTF(("%s: sleep\n", __FUNCTION__));
    504 		error = tsleep(sc->sc_frames, PZERO | PCATCH, "irtrd", 0);
    505 		DPRINTF(("%s: woke, error=%d\n", __FUNCTION__, error));
    506 		if (error) {
    507 			sc->sc_state &= ~IRT_RSLP;
    508 			break;
    509 		}
    510 	}
    511 
    512 	/* Do just one frame transfer per read */
    513 	if (!error) {
    514 		if (uio->uio_resid < sc->sc_frames[sc->sc_frameo].len) {
    515 			DPRINTF(("%s: uio buffer smaller than frame size (%d < %d)\n", __FUNCTION__, uio->uio_resid, sc->sc_frames[sc->sc_frameo].len));
    516 			error = EINVAL;
    517 		} else {
    518 			DPRINTF(("%s: moving %d bytes\n", __FUNCTION__,
    519 				 sc->sc_frames[sc->sc_frameo].len));
    520 				error = uiomove(sc->sc_frames[sc->sc_frameo].buf,
    521 					sc->sc_frames[sc->sc_frameo].len, uio);
    522 		}
    523 		sc->sc_frameo++;
    524 		sc->sc_nframes--;
    525 	}
    526 	splx(s);
    527 
    528 	return (error);
    529 }
    530 
    531 int
    532 irt_putc(int c, struct tty *tp)
    533 {
    534 	int s;
    535 	int error;
    536 
    537 	if (tp->t_outq.c_cc > tp->t_hiwat) {
    538 		irframetstart(tp);
    539 		s = spltty();
    540 		/*
    541 		 * This can only occur if FLUSHO is set in t_lflag,
    542 		 * or if ttstart/oproc is synchronous (or very fast).
    543 		 */
    544 		if (tp->t_outq.c_cc <= tp->t_hiwat) {
    545 			splx(s);
    546 			goto go;
    547 		}
    548 		SET(tp->t_state, TS_ASLEEP);
    549 		error = ttysleep(tp, &tp->t_outq, TTOPRI | PCATCH, ttyout, 0);
    550 		splx(s);
    551 		if (error)
    552 			return (error);
    553 	}
    554  go:
    555 	if (putc(c, &tp->t_rawq) < 0) {
    556 		printf("irframe: putc failed\n");
    557 		return (EIO);
    558 	}
    559 	return (0);
    560 }
    561 
    562 int
    563 irt_putesc(int c, struct tty *tp)
    564 {
    565 	int error;
    566 
    567 	if (c == SIR_BOF || c == SIR_EOF || c == SIR_CE) {
    568 		error = irt_putc(SIR_CE, tp);
    569 		if (!error)
    570 			error = irt_putc(SIR_ESC_BIT^c, tp);
    571 	} else {
    572 		error = irt_putc(c, tp);
    573 	}
    574 	return (error);
    575 }
    576 
    577 int
    578 irframet_write(void *h, struct uio *uio, int flag)
    579 {
    580 	u_int8_t buf[MAX_IRDA_FRAME];
    581 	size_t n;
    582 	int error;
    583 
    584 	DPRINTF(("%s\n", __FUNCTION__));
    585 
    586 	n = uio->uio_resid;
    587 	if (n > MAX_IRDA_FRAME)
    588 		return (EINVAL);
    589 	error = uiomove(buf, n, uio);
    590 	if (error)
    591 		return (error);
    592 	return (irt_write_buf(h, buf, n));
    593 }
    594 
    595 int
    596 irt_write_buf(void *h, void *buf, size_t len)
    597 {
    598 	struct tty *tp = h;
    599 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    600 	u_int8_t *cp = buf;
    601 	int c, error, ofcs, i;
    602 
    603 	DPRINTF(("%s: tp=%p len=%d\n", __FUNCTION__, tp, len));
    604 
    605 	ofcs = INITFCS;
    606 	error = 0;
    607 
    608 	for (i = 0; i < sc->sc_ebofs; i++)
    609 		irt_putc(SIR_EXTRA_BOF, tp);
    610 	irt_putc(SIR_BOF, tp);
    611 
    612 	while (len-- > 0) {
    613 		c = *cp++;
    614 		ofcs = updateFCS(ofcs, c);
    615 		error = irt_putesc(c, tp);
    616 		if (error)
    617 			return (error);
    618 	}
    619 
    620 	ofcs = ~ofcs;
    621 	error = irt_putesc(ofcs & 0xff, tp);
    622 	if (!error)
    623 		error = irt_putesc((ofcs >> 8) & 0xff, tp);
    624 	if (!error)
    625 		error = irt_putc(SIR_EOF, tp);
    626 
    627 	irframetstart(tp);
    628 
    629 	return (error);
    630 }
    631 
    632 int
    633 irframet_poll(void *h, int events, struct proc *p)
    634 {
    635 	struct tty *tp = h;
    636 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    637 	int revents = 0;
    638 	int s;
    639 
    640 	DPRINTF(("%s: sc=%p\n", __FUNCTION__, sc));
    641 
    642 	s = splir();
    643 	/* XXX should check with tty */
    644 	if (events & (POLLOUT | POLLWRNORM))
    645 		revents |= events & (POLLOUT | POLLWRNORM);
    646 	if (events & (POLLIN | POLLRDNORM)) {
    647 		if (sc->sc_nframes > 0) {
    648 			DPRINTF(("%s: have data\n", __FUNCTION__));
    649 			revents |= events & (POLLIN | POLLRDNORM);
    650 		} else {
    651 			DPRINTF(("%s: recording select", __FUNCTION__));
    652 			selrecord(p, &sc->sc_rsel);
    653 		}
    654 	}
    655 	splx(s);
    656 
    657 	return (revents);
    658 }
    659 
    660 int
    661 irframet_set_params(void *h, struct irda_params *p)
    662 {
    663 	struct tty *tp = h;
    664 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    665 	struct termios tt;
    666 	int i;
    667 
    668 	DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
    669 
    670 	if (p->speed != sc->sc_speed) {
    671 		switch (p->speed) {
    672 		case   2400:
    673 		case   9600:
    674 		case  19200:
    675 		case  38400:
    676 		case  57600:
    677 		case 115200:
    678 			break;
    679 		default: return (EINVAL);
    680 		}
    681 		ttioctl(tp, TIOCGETA,  (caddr_t)&tt, 0, curproc);
    682 		sc->sc_speed = tt.c_ispeed = tt.c_ospeed = p->speed;
    683 		ttioctl(tp, TIOCSETAF, (caddr_t)&tt, 0, curproc);
    684 	}
    685 
    686 	sc->sc_ebofs = p->ebofs;
    687 	if (sc->sc_maxsize != p->maxsize) {
    688 		sc->sc_maxsize = p->maxsize;
    689 		if (sc->sc_inbuf != NULL)
    690 			free(sc->sc_inbuf, M_DEVBUF);
    691 		for (i = 0; i < MAXFRAMES; i++)
    692 			if (sc->sc_frames[i].buf != NULL)
    693 				free(sc->sc_frames[i].buf, M_DEVBUF);
    694 		if (sc->sc_maxsize != 0) {
    695 			sc->sc_inbuf = malloc(sc->sc_maxsize+2, M_DEVBUF,
    696 					      M_WAITOK);
    697 			for (i = 0; i < MAXFRAMES; i++)
    698 				sc->sc_frames[i].buf = malloc(sc->sc_maxsize,
    699 							   M_DEVBUF, M_WAITOK);
    700 		} else {
    701 			sc->sc_inbuf = NULL;
    702 			for (i = 0; i < MAXFRAMES; i++)
    703 				sc->sc_frames[i].buf = NULL;
    704 		}
    705 	}
    706 	sc->sc_framestate = FRAME_OUTSIDE;
    707 
    708 	return (0);
    709 }
    710 
    711 int
    712 irframet_get_speeds(void *h, int *speeds)
    713 {
    714 	struct tty *tp = h;
    715 
    716 	tp = tp;
    717 	DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
    718 	*speeds = IRDA_SPEEDS_SIR;
    719 	return (0);
    720 }
    721 
    722 int
    723 irframet_get_turnarounds(void *h, int *turnarounds)
    724 {
    725 	struct tty *tp = h;
    726 
    727 	tp = tp;
    728 	DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
    729 	*turnarounds = IRDA_TURNT_10000;
    730 	return (0);
    731 }
    732