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