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