Home | History | Annotate | Line # | Download | only in ir
irframe_tty.c revision 1.3
      1 /*	$NetBSD: irframe_tty.c,v 1.3 2001/12/04 20:53:21 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 	return (0);
    252 }
    253 
    254 /*
    255  * Line specific close routine, called from device close routine
    256  * and from ttioctl.
    257  * Detach the tty from the irframe unit.
    258  * Mimics part of ttyclose().
    259  */
    260 int
    261 irframetclose(struct tty *tp, int flag)
    262 {
    263 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    264 	int s;
    265 
    266 	DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
    267 
    268 	s = spltty();
    269 	ttyflush(tp, FREAD | FWRITE);
    270 	tp->t_linesw = linesw[0]; /* default line discipline */
    271 	if (sc != NULL) {
    272 		tp->t_sc = NULL;
    273 		printf("%s detached from tty%02d\n", sc->sc_irp.sc_dev.dv_xname,
    274 		    minor(tp->t_dev));
    275 
    276 		if (sc->sc_tp == tp)
    277 			irframe_dealloc(&sc->sc_irp.sc_dev);
    278 	}
    279 	splx(s);
    280 	return (0);
    281 }
    282 
    283 /*
    284  * Line specific (tty) ioctl routine.
    285  * This discipline requires that tty device drivers call
    286  * the line specific l_ioctl routine from their ioctl routines.
    287  */
    288 /* ARGSUSED */
    289 int
    290 irframetioctl(struct tty *tp, u_long cmd, caddr_t data, int flag,
    291 	     struct proc *p)
    292 {
    293 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    294 	int error;
    295 
    296 	DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
    297 
    298 	if (sc == NULL || tp != sc->sc_tp)
    299 		return (-1);
    300 
    301 	error = 0;
    302 	switch (cmd) {
    303 	default:
    304 #if 0
    305 		error = irframeioctl(sc, cmd, data, flag, p);
    306 #else
    307 		error = EINVAL;
    308 #endif
    309 		break;
    310 	}
    311 
    312 	return (error);
    313 }
    314 
    315 /*
    316  * Start output on async tty interface.  If the transmit queue
    317  * has drained sufficiently, arrange for irframeasyncstart to be
    318  * called later at splsoftnet.
    319  * Called at spltty or higher.
    320  */
    321 int
    322 irframetstart(struct tty *tp)
    323 {
    324 	/*struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;*/
    325 
    326 	DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
    327 
    328 	/*
    329 	 * If there is stuff in the output queue, send it now.
    330 	 * We are being called in lieu of ttstart and must do what it would.
    331 	 */
    332 	if (tp->t_oproc != NULL)
    333 		(*tp->t_oproc)(tp);
    334 
    335 	return (0);
    336 }
    337 
    338 void
    339 irt_frame(struct irframet_softc *sc, u_char *buf, u_int len)
    340 {
    341 	if (sc->sc_nframes >= MAXFRAMES) {
    342 #ifdef IRFRAMET_DEBUG
    343 		printf("%s: dropped frame\n", __FUNCTION__);
    344 #endif
    345 		return;
    346 	}
    347 	if (sc->sc_frames[sc->sc_framei].buf == NULL)
    348 		return;
    349 	memcpy(sc->sc_frames[sc->sc_framei].buf, buf, len);
    350 	sc->sc_frames[sc->sc_framei].len = len;
    351 	sc->sc_framei = (sc->sc_framei+1) % MAXFRAMES;
    352 	sc->sc_nframes++;
    353 	if (sc->sc_state & IRT_RSLP) {
    354 		sc->sc_state &= ~IRT_RSLP;
    355 		DPRINTF(("%s: waking up reader\n", __FUNCTION__));
    356 		wakeup(sc->sc_frames);
    357 	}
    358 	selwakeup(&sc->sc_rsel);
    359 }
    360 
    361 void
    362 irt_timeout(void *v)
    363 {
    364 	struct irframet_softc *sc = v;
    365 
    366 #ifdef IRFRAMET_DEBUG
    367 	if (sc->sc_framestate != FRAME_OUTSIDE)
    368 		printf("%s: input frame timeout\n", __FUNCTION__);
    369 #endif
    370 	sc->sc_framestate = FRAME_OUTSIDE;
    371 }
    372 
    373 int
    374 irframetinput(int c, struct tty *tp)
    375 {
    376 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    377 
    378 	DPRINTF(("%s: tp=%p c=0x%0x\n", __FUNCTION__, tp, c));
    379 
    380 	if (sc == NULL || tp != (struct tty *)sc->sc_tp)
    381 		return (0);
    382 
    383 	if (sc->sc_inbuf == NULL)
    384 		return (0);
    385 
    386 	switch (c) {
    387 	case SIR_BOF:
    388 		sc->sc_framestate = FRAME_INSIDE;
    389 		sc->sc_inchars = 0;
    390 		sc->sc_inFCS = INITFCS;
    391 		break;
    392 	case SIR_EOF:
    393 		if (sc->sc_framestate == FRAME_INSIDE &&
    394 		    sc->sc_inchars >= 4 && sc->sc_inFCS == GOODFCS) {
    395 			irt_frame(sc, sc->sc_inbuf, sc->sc_inchars - 2);
    396 		} else if (sc->sc_framestate != FRAME_OUTSIDE) {
    397 #ifdef IRFRAMET_DEBUG
    398 			printf("%s: malformed input frame\n", __FUNCTION__);
    399 #endif
    400 		}
    401 		sc->sc_framestate = FRAME_OUTSIDE;
    402 		break;
    403 	case SIR_CE:
    404 		if (sc->sc_framestate == FRAME_INSIDE)
    405 			sc->sc_framestate = FRAME_ESCAPE;
    406 		break;
    407 	default:
    408 		if (sc->sc_framestate != FRAME_OUTSIDE) {
    409 			if (sc->sc_framestate == FRAME_ESCAPE) {
    410 				sc->sc_framestate = FRAME_INSIDE;
    411 				c ^= SIR_ESC_BIT;
    412 			}
    413 			if (sc->sc_inchars < sc->sc_maxsize + 2) {
    414 				sc->sc_inbuf[sc->sc_inchars++] = c;
    415 				sc->sc_inFCS = updateFCS(sc->sc_inFCS, c);
    416 			} else {
    417 				sc->sc_framestate = FRAME_OUTSIDE;
    418 #ifdef IRFRAMET_DEBUG
    419 				printf("%s: input frame overrun\n",
    420 				       __FUNCTION__);
    421 #endif
    422 			}
    423 		}
    424 		break;
    425 	}
    426 
    427 	if (sc->sc_framestate != FRAME_OUTSIDE) {
    428 		callout_reset(&sc->sc_timeout, hz/100, irt_timeout, sc);
    429 	}
    430 
    431 	return (0);
    432 }
    433 
    434 
    435 /*** irframe methods ***/
    436 
    437 int
    438 irframet_open(void *h, int flag, int mode, struct proc *p)
    439 {
    440 	struct tty *tp = h;
    441 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    442 
    443 	DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
    444 
    445 	sc->sc_ebofs = IRDA_DEFAULT_EBOFS;
    446 	sc->sc_maxsize = 0;
    447 	sc->sc_framestate = FRAME_OUTSIDE;
    448 	sc->sc_nframes = 0;
    449 	sc->sc_framei = 0;
    450 	sc->sc_frameo = 0;
    451 	callout_init(&sc->sc_timeout);
    452 
    453 	return (0);
    454 }
    455 
    456 int
    457 irframet_close(void *h, int flag, int mode, struct proc *p)
    458 {
    459 	struct tty *tp = h;
    460 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    461 	int i, s;
    462 
    463 	DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
    464 
    465 	callout_stop(&sc->sc_timeout);
    466 	s = splir();
    467 	if (sc->sc_inbuf != NULL) {
    468 		free(sc->sc_inbuf, M_DEVBUF);
    469 		sc->sc_inbuf = NULL;
    470 	}
    471 	for (i = 0; i < MAXFRAMES; i++) {
    472 		if (sc->sc_frames[i].buf != NULL) {
    473 			free(sc->sc_frames[i].buf, M_DEVBUF);
    474 			sc->sc_frames[i].buf = NULL;
    475 		}
    476 	}
    477 	splx(s);
    478 
    479 	return (0);
    480 }
    481 
    482 int
    483 irframet_read(void *h, struct uio *uio, int flag)
    484 {
    485 	struct tty *tp = h;
    486 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    487 	int error = 0;
    488 	int s;
    489 
    490 	DPRINTF(("%s: resid=%d, iovcnt=%d, offset=%ld\n",
    491 		 __FUNCTION__, uio->uio_resid, uio->uio_iovcnt,
    492 		 (long)uio->uio_offset));
    493 
    494 	s = splir();
    495 	while (sc->sc_nframes == 0) {
    496 		if (flag & IO_NDELAY) {
    497 			splx(s);
    498 			return (EWOULDBLOCK);
    499 		}
    500 		sc->sc_state |= IRT_RSLP;
    501 		DPRINTF(("%s: sleep\n", __FUNCTION__));
    502 		error = tsleep(sc->sc_frames, PZERO | PCATCH, "irtrd", 0);
    503 		DPRINTF(("%s: woke, error=%d\n", __FUNCTION__, error));
    504 		if (error) {
    505 			sc->sc_state &= ~IRT_RSLP;
    506 			break;
    507 		}
    508 	}
    509 
    510 	/* Do just one frame transfer per read */
    511 	if (!error) {
    512 		if (uio->uio_resid < sc->sc_frames[sc->sc_frameo].len) {
    513 			DPRINTF(("%s: uio buffer smaller than frame size (%d < %d)\n", __FUNCTION__, uio->uio_resid, sc->sc_frames[sc->sc_frameo].len));
    514 			error = EINVAL;
    515 		} else {
    516 			DPRINTF(("%s: moving %d bytes\n", __FUNCTION__,
    517 				 sc->sc_frames[sc->sc_frameo].len));
    518 				error = uiomove(sc->sc_frames[sc->sc_frameo].buf,
    519 					sc->sc_frames[sc->sc_frameo].len, uio);
    520 		}
    521 		sc->sc_frameo++;
    522 		sc->sc_nframes--;
    523 	}
    524 	splx(s);
    525 
    526 	return (error);
    527 }
    528 
    529 int
    530 irt_putc(int c, struct tty *tp)
    531 {
    532 	int s;
    533 	int error;
    534 
    535 	if (tp->t_outq.c_cc > tp->t_hiwat) {
    536 		irframetstart(tp);
    537 		s = spltty();
    538 		/*
    539 		 * This can only occur if FLUSHO is set in t_lflag,
    540 		 * or if ttstart/oproc is synchronous (or very fast).
    541 		 */
    542 		if (tp->t_outq.c_cc <= tp->t_hiwat) {
    543 			splx(s);
    544 			goto go;
    545 		}
    546 		SET(tp->t_state, TS_ASLEEP);
    547 		error = ttysleep(tp, &tp->t_outq, TTOPRI | PCATCH, ttyout, 0);
    548 		splx(s);
    549 		if (error)
    550 			return (error);
    551 	}
    552  go:
    553 	if (putc(c, &tp->t_rawq) < 0) {
    554 		printf("irframe: putc failed\n");
    555 		return (EIO);
    556 	}
    557 	return (0);
    558 }
    559 
    560 int
    561 irt_putesc(int c, struct tty *tp)
    562 {
    563 	int error;
    564 
    565 	if (c == SIR_BOF || c == SIR_EOF || c == SIR_CE) {
    566 		error = irt_putc(SIR_CE, tp);
    567 		if (!error)
    568 			error = irt_putc(SIR_ESC_BIT^c, tp);
    569 	} else {
    570 		error = irt_putc(c, tp);
    571 	}
    572 	return (error);
    573 }
    574 
    575 int
    576 irframet_write(void *h, struct uio *uio, int flag)
    577 {
    578 	u_int8_t buf[MAX_IRDA_FRAME];
    579 	size_t n;
    580 	int error;
    581 
    582 	DPRINTF(("%s\n", __FUNCTION__));
    583 
    584 	n = uio->uio_resid;
    585 	if (n > MAX_IRDA_FRAME)
    586 		return (EINVAL);
    587 	error = uiomove(buf, n, uio);
    588 	if (error)
    589 		return (error);
    590 	return (irt_write_buf(h, buf, n));
    591 }
    592 
    593 int
    594 irt_write_buf(void *h, void *buf, size_t len)
    595 {
    596 	struct tty *tp = h;
    597 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    598 	u_int8_t *cp = buf;
    599 	int c, error, ofcs, i;
    600 
    601 	DPRINTF(("%s: tp=%p len=%d\n", __FUNCTION__, tp, len));
    602 
    603 	ofcs = INITFCS;
    604 	error = 0;
    605 
    606 	for (i = 0; i < sc->sc_ebofs; i++)
    607 		irt_putc(SIR_EXTRA_BOF, tp);
    608 	irt_putc(SIR_BOF, tp);
    609 
    610 	while (len-- > 0) {
    611 		c = *cp++;
    612 		ofcs = updateFCS(ofcs, c);
    613 		error = irt_putesc(c, tp);
    614 		if (error)
    615 			return (error);
    616 	}
    617 
    618 	ofcs = ~ofcs;
    619 	error = irt_putesc(ofcs & 0xff, tp);
    620 	if (!error)
    621 		error = irt_putesc((ofcs >> 8) & 0xff, tp);
    622 	if (!error)
    623 		error = irt_putc(SIR_EOF, tp);
    624 
    625 	irframetstart(tp);
    626 
    627 	return (error);
    628 }
    629 
    630 int
    631 irframet_poll(void *h, int events, struct proc *p)
    632 {
    633 	struct tty *tp = h;
    634 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    635 	int revents = 0;
    636 	int s;
    637 
    638 	DPRINTF(("%s: sc=%p\n", __FUNCTION__, sc));
    639 
    640 	s = splir();
    641 	/* XXX should check with tty */
    642 	if (events & (POLLOUT | POLLWRNORM))
    643 		revents |= events & (POLLOUT | POLLWRNORM);
    644 	if (events & (POLLIN | POLLRDNORM)) {
    645 		if (sc->sc_nframes > 0) {
    646 			DPRINTF(("%s: have data\n", __FUNCTION__));
    647 			revents |= events & (POLLIN | POLLRDNORM);
    648 		} else {
    649 			DPRINTF(("%s: recording select", __FUNCTION__));
    650 			selrecord(p, &sc->sc_rsel);
    651 		}
    652 	}
    653 	splx(s);
    654 
    655 	return (revents);
    656 }
    657 
    658 int
    659 irframet_set_params(void *h, struct irda_params *p)
    660 {
    661 	struct tty *tp = h;
    662 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    663 	struct termios tt;
    664 	int i;
    665 
    666 	DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
    667 
    668 	switch (p->speed) {
    669 	case   2400:
    670 	case   9600:
    671 	case  19200:
    672 	case  38400:
    673 	case  57600:
    674 	case 115200:
    675 		break;
    676 	default: return (EINVAL);
    677 	}
    678 	ttioctl(tp, TIOCGETA,  (caddr_t)&tt, 0, curproc);
    679 	tt.c_ispeed = tt.c_ospeed = p->speed;
    680 	ttioctl(tp, TIOCSETAF, (caddr_t)&tt, 0, curproc);
    681 
    682 	sc->sc_ebofs = p->ebofs;
    683 	if (sc->sc_maxsize != p->maxsize) {
    684 		sc->sc_maxsize = p->maxsize;
    685 		if (sc->sc_inbuf != NULL)
    686 			free(sc->sc_inbuf, M_DEVBUF);
    687 		for (i = 0; i < MAXFRAMES; i++)
    688 			if (sc->sc_frames[i].buf != NULL)
    689 				free(sc->sc_frames[i].buf, M_DEVBUF);
    690 		if (sc->sc_maxsize != 0) {
    691 			sc->sc_inbuf = malloc(sc->sc_maxsize+2, M_DEVBUF,
    692 					      M_WAITOK);
    693 			for (i = 0; i < MAXFRAMES; i++)
    694 				sc->sc_frames[i].buf = malloc(sc->sc_maxsize,
    695 							   M_DEVBUF, M_WAITOK);
    696 		} else {
    697 			sc->sc_inbuf = NULL;
    698 			for (i = 0; i < MAXFRAMES; i++)
    699 				sc->sc_frames[i].buf = NULL;
    700 		}
    701 	}
    702 	sc->sc_framestate = FRAME_OUTSIDE;
    703 
    704 	return (0);
    705 }
    706 
    707 int
    708 irframet_get_speeds(void *h, int *speeds)
    709 {
    710 	struct tty *tp = h;
    711 
    712 	tp = tp;
    713 	DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
    714 	*speeds = IRDA_SPEEDS_SIR;
    715 	return (0);
    716 }
    717 
    718 int
    719 irframet_get_turnarounds(void *h, int *turnarounds)
    720 {
    721 	struct tty *tp = h;
    722 
    723 	tp = tp;
    724 	DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
    725 	*turnarounds = IRDA_TURNT_10000;
    726 	return (0);
    727 }
    728