Home | History | Annotate | Line # | Download | only in ir
irframe_tty.c revision 1.7
      1 /*	$NetBSD: irframe_tty.c,v 1.7 2001/12/05 04:07:06 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=%s\n", __FUNCTION__, tp->t_linesw,
    239 		 tp->t_linesw->l_name));
    240 	if (strcmp(tp->t_linesw->l_name, "irframe") == 0) { /* XXX */
    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 	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 	printf("%s attached at tty%02d\n", sc->sc_irp.sc_dev.dv_xname,
    254 	    minor(tp->t_dev));
    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 	DPRINTF(("%s: nframe=%d framei=%d frameo=%d\n",
    364 		 __FUNCTION__, sc->sc_nframes, sc->sc_framei, sc->sc_frameo));
    365 
    366 	if (sc->sc_nframes >= MAXFRAMES) {
    367 #ifdef IRFRAMET_DEBUG
    368 		printf("%s: dropped frame\n", __FUNCTION__);
    369 #endif
    370 		return;
    371 	}
    372 	if (sc->sc_frames[sc->sc_framei].buf == NULL)
    373 		return;
    374 	memcpy(sc->sc_frames[sc->sc_framei].buf, buf, len);
    375 	sc->sc_frames[sc->sc_framei].len = len;
    376 	sc->sc_framei = (sc->sc_framei+1) % MAXFRAMES;
    377 	sc->sc_nframes++;
    378 	if (sc->sc_state & IRT_RSLP) {
    379 		sc->sc_state &= ~IRT_RSLP;
    380 		DPRINTF(("%s: waking up reader\n", __FUNCTION__));
    381 		wakeup(sc->sc_frames);
    382 	}
    383 	selwakeup(&sc->sc_rsel);
    384 }
    385 
    386 void
    387 irt_timeout(void *v)
    388 {
    389 	struct irframet_softc *sc = v;
    390 
    391 #ifdef IRFRAMET_DEBUG
    392 	if (sc->sc_framestate != FRAME_OUTSIDE)
    393 		printf("%s: input frame timeout\n", __FUNCTION__);
    394 #endif
    395 	sc->sc_framestate = FRAME_OUTSIDE;
    396 }
    397 
    398 int
    399 irframetinput(int c, struct tty *tp)
    400 {
    401 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    402 
    403 	c &= 0xff;
    404 
    405 #if IRFRAMET_DEBUG
    406 	if (irframetdebug > 1)
    407 		DPRINTF(("%s: tp=%p c=0x%02x\n", __FUNCTION__, tp, c));
    408 #endif
    409 
    410 	if (sc == NULL || tp != (struct tty *)sc->sc_tp)
    411 		return (0);
    412 
    413 	if (sc->sc_inbuf == NULL)
    414 		return (0);
    415 
    416 	switch (c) {
    417 	case SIR_BOF:
    418 		DPRINTF(("%s: BOF\n", __FUNCTION__));
    419 		sc->sc_framestate = FRAME_INSIDE;
    420 		sc->sc_inchars = 0;
    421 		sc->sc_inFCS = INITFCS;
    422 		break;
    423 	case SIR_EOF:
    424 		DPRINTF(("%s: EOF state=%d inchars=%d fcs=0x%04x\n",
    425 			 __FUNCTION__,
    426 			 sc->sc_framestate, sc->sc_inchars, sc->sc_inFCS));
    427 		if (sc->sc_framestate == FRAME_INSIDE &&
    428 		    sc->sc_inchars >= 4 && sc->sc_inFCS == GOODFCS) {
    429 			irt_frame(sc, sc->sc_inbuf, sc->sc_inchars - 2);
    430 		} else if (sc->sc_framestate != FRAME_OUTSIDE) {
    431 #ifdef IRFRAMET_DEBUG
    432 			printf("%s: malformed input frame\n", __FUNCTION__);
    433 #endif
    434 		}
    435 		sc->sc_framestate = FRAME_OUTSIDE;
    436 		break;
    437 	case SIR_CE:
    438 		DPRINTF(("%s: CE\n", __FUNCTION__));
    439 		if (sc->sc_framestate == FRAME_INSIDE)
    440 			sc->sc_framestate = FRAME_ESCAPE;
    441 		break;
    442 	default:
    443 		DPRINTF(("%s: c=0x%02x, inchar=%d state=%d\n", __FUNCTION__, c,
    444 			 sc->sc_inchars, sc->sc_state));
    445 		if (sc->sc_framestate != FRAME_OUTSIDE) {
    446 			if (sc->sc_framestate == FRAME_ESCAPE) {
    447 				sc->sc_framestate = FRAME_INSIDE;
    448 				c ^= SIR_ESC_BIT;
    449 			}
    450 			if (sc->sc_inchars < sc->sc_maxsize + 2) {
    451 				sc->sc_inbuf[sc->sc_inchars++] = c;
    452 				sc->sc_inFCS = updateFCS(sc->sc_inFCS, c);
    453 			} else {
    454 				sc->sc_framestate = FRAME_OUTSIDE;
    455 #ifdef IRFRAMET_DEBUG
    456 				printf("%s: input frame overrun\n",
    457 				       __FUNCTION__);
    458 #endif
    459 			}
    460 		}
    461 		break;
    462 	}
    463 
    464 #if 1
    465 	if (sc->sc_framestate != FRAME_OUTSIDE) {
    466 		callout_reset(&sc->sc_timeout, hz/20, irt_timeout, sc);
    467 	}
    468 #endif
    469 
    470 	return (0);
    471 }
    472 
    473 
    474 /*** irframe methods ***/
    475 
    476 int
    477 irframet_open(void *h, int flag, int mode, struct proc *p)
    478 {
    479 	struct tty *tp = h;
    480 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    481 
    482 	DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
    483 
    484 	sc->sc_speed = 0;
    485 	sc->sc_ebofs = IRDA_DEFAULT_EBOFS;
    486 	sc->sc_maxsize = 0;
    487 	sc->sc_framestate = FRAME_OUTSIDE;
    488 	sc->sc_nframes = 0;
    489 	sc->sc_framei = 0;
    490 	sc->sc_frameo = 0;
    491 	callout_init(&sc->sc_timeout);
    492 
    493 	return (0);
    494 }
    495 
    496 int
    497 irframet_close(void *h, int flag, int mode, struct proc *p)
    498 {
    499 	struct tty *tp = h;
    500 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    501 	int i, s;
    502 
    503 	DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
    504 
    505 	callout_stop(&sc->sc_timeout);
    506 	s = splir();
    507 	if (sc->sc_inbuf != NULL) {
    508 		free(sc->sc_inbuf, M_DEVBUF);
    509 		sc->sc_inbuf = NULL;
    510 	}
    511 	for (i = 0; i < MAXFRAMES; i++) {
    512 		if (sc->sc_frames[i].buf != NULL) {
    513 			free(sc->sc_frames[i].buf, M_DEVBUF);
    514 			sc->sc_frames[i].buf = NULL;
    515 		}
    516 	}
    517 	splx(s);
    518 
    519 	return (0);
    520 }
    521 
    522 int
    523 irframet_read(void *h, struct uio *uio, int flag)
    524 {
    525 	struct tty *tp = h;
    526 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    527 	int error = 0;
    528 	int s;
    529 
    530 	DPRINTF(("%s: resid=%d, iovcnt=%d, offset=%ld\n",
    531 		 __FUNCTION__, uio->uio_resid, uio->uio_iovcnt,
    532 		 (long)uio->uio_offset));
    533 	DPRINTF(("%s: nframe=%d framei=%d frameo=%d\n",
    534 		 __FUNCTION__, sc->sc_nframes, sc->sc_framei, sc->sc_frameo));
    535 
    536 
    537 	s = splir();
    538 	while (sc->sc_nframes == 0) {
    539 		if (flag & IO_NDELAY) {
    540 			splx(s);
    541 			return (EWOULDBLOCK);
    542 		}
    543 		sc->sc_state |= IRT_RSLP;
    544 		DPRINTF(("%s: sleep\n", __FUNCTION__));
    545 		error = tsleep(sc->sc_frames, PZERO | PCATCH, "irtrd", 0);
    546 		DPRINTF(("%s: woke, error=%d\n", __FUNCTION__, error));
    547 		if (error) {
    548 			sc->sc_state &= ~IRT_RSLP;
    549 			break;
    550 		}
    551 	}
    552 
    553 	/* Do just one frame transfer per read */
    554 	if (!error) {
    555 		if (uio->uio_resid < sc->sc_frames[sc->sc_frameo].len) {
    556 			DPRINTF(("%s: uio buffer smaller than frame size (%d < %d)\n", __FUNCTION__, uio->uio_resid, sc->sc_frames[sc->sc_frameo].len));
    557 			error = EINVAL;
    558 		} else {
    559 			DPRINTF(("%s: moving %d bytes\n", __FUNCTION__,
    560 				 sc->sc_frames[sc->sc_frameo].len));
    561 			error = uiomove(sc->sc_frames[sc->sc_frameo].buf,
    562 					sc->sc_frames[sc->sc_frameo].len, uio);
    563 			DPRINTF(("%s: error=%d\n", __FUNCTION__, error));
    564 		}
    565 		sc->sc_frameo = (sc->sc_frameo+1) % MAXFRAMES;
    566 		sc->sc_nframes--;
    567 	}
    568 	splx(s);
    569 
    570 	return (error);
    571 }
    572 
    573 int
    574 irt_putc(int c, struct tty *tp)
    575 {
    576 	int s;
    577 	int error;
    578 
    579 	if (tp->t_outq.c_cc > tp->t_hiwat) {
    580 		irframetstart(tp);
    581 		s = spltty();
    582 		/*
    583 		 * This can only occur if FLUSHO is set in t_lflag,
    584 		 * or if ttstart/oproc is synchronous (or very fast).
    585 		 */
    586 		if (tp->t_outq.c_cc <= tp->t_hiwat) {
    587 			splx(s);
    588 			goto go;
    589 		}
    590 		SET(tp->t_state, TS_ASLEEP);
    591 		error = ttysleep(tp, &tp->t_outq, TTOPRI | PCATCH, ttyout, 0);
    592 		splx(s);
    593 		if (error)
    594 			return (error);
    595 	}
    596  go:
    597 	if (putc(c, &tp->t_rawq) < 0) {
    598 		printf("irframe: putc failed\n");
    599 		return (EIO);
    600 	}
    601 	return (0);
    602 }
    603 
    604 int
    605 irt_putesc(int c, struct tty *tp)
    606 {
    607 	int error;
    608 
    609 	if (c == SIR_BOF || c == SIR_EOF || c == SIR_CE) {
    610 		error = irt_putc(SIR_CE, tp);
    611 		if (!error)
    612 			error = irt_putc(SIR_ESC_BIT^c, tp);
    613 	} else {
    614 		error = irt_putc(c, tp);
    615 	}
    616 	return (error);
    617 }
    618 
    619 int
    620 irframet_write(void *h, struct uio *uio, int flag)
    621 {
    622 	u_int8_t buf[MAX_IRDA_FRAME];
    623 	size_t n;
    624 	int error;
    625 
    626 	DPRINTF(("%s: resid=%d, iovcnt=%d, offset=%ld\n",
    627 		 __FUNCTION__, uio->uio_resid, uio->uio_iovcnt,
    628 		 (long)uio->uio_offset));
    629 
    630 	n = uio->uio_resid;
    631 	if (n > MAX_IRDA_FRAME)
    632 		return (EINVAL);
    633 	error = uiomove(buf, n, uio);
    634 	if (error)
    635 		return (error);
    636 	return (irt_write_buf(h, buf, n));
    637 }
    638 
    639 int
    640 irt_write_buf(void *h, void *buf, size_t len)
    641 {
    642 	struct tty *tp = h;
    643 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    644 	u_int8_t *cp = buf;
    645 	int c, error, ofcs, i;
    646 
    647 	DPRINTF(("%s: tp=%p len=%d\n", __FUNCTION__, tp, len));
    648 
    649 	ofcs = INITFCS;
    650 	error = 0;
    651 
    652 	for (i = 0; i < sc->sc_ebofs; i++)
    653 		irt_putc(SIR_EXTRA_BOF, tp);
    654 	irt_putc(SIR_BOF, tp);
    655 
    656 	while (len-- > 0) {
    657 		c = *cp++;
    658 		ofcs = updateFCS(ofcs, c);
    659 		error = irt_putesc(c, tp);
    660 		if (error)
    661 			return (error);
    662 	}
    663 
    664 	ofcs = ~ofcs;
    665 	error = irt_putesc(ofcs & 0xff, tp);
    666 	if (!error)
    667 		error = irt_putesc((ofcs >> 8) & 0xff, tp);
    668 	if (!error)
    669 		error = irt_putc(SIR_EOF, tp);
    670 
    671 	irframetstart(tp);
    672 
    673 	DPRINTF(("%s: done\n", __FUNCTION__));
    674 
    675 	return (error);
    676 }
    677 
    678 int
    679 irframet_poll(void *h, int events, struct proc *p)
    680 {
    681 	struct tty *tp = h;
    682 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    683 	int revents = 0;
    684 	int s;
    685 
    686 	DPRINTF(("%s: sc=%p\n", __FUNCTION__, sc));
    687 
    688 	s = splir();
    689 	/* XXX should check with tty */
    690 	if (events & (POLLOUT | POLLWRNORM))
    691 		revents |= events & (POLLOUT | POLLWRNORM);
    692 	if (events & (POLLIN | POLLRDNORM)) {
    693 		if (sc->sc_nframes > 0) {
    694 			DPRINTF(("%s: have data\n", __FUNCTION__));
    695 			revents |= events & (POLLIN | POLLRDNORM);
    696 		} else {
    697 			DPRINTF(("%s: recording select\n", __FUNCTION__));
    698 			selrecord(p, &sc->sc_rsel);
    699 		}
    700 	}
    701 	splx(s);
    702 
    703 	return (revents);
    704 }
    705 
    706 int
    707 irframet_set_params(void *h, struct irda_params *p)
    708 {
    709 	struct tty *tp = h;
    710 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    711 	struct termios tt;
    712 	int i;
    713 
    714 	DPRINTF(("%s: tp=%p speed=%d ebofs=%d maxsize=%d\n",
    715 		 __FUNCTION__, tp, p->speed, p->ebofs, p->maxsize));
    716 
    717 	if (p->speed != sc->sc_speed) {
    718 		switch (p->speed) {
    719 		case   2400:
    720 		case   9600:
    721 		case  19200:
    722 		case  38400:
    723 		case  57600:
    724 		case 115200:
    725 			break;
    726 		default: return (EINVAL);
    727 		}
    728 		ttioctl(tp, TIOCGETA,  (caddr_t)&tt, 0, curproc);
    729 		sc->sc_speed = tt.c_ispeed = tt.c_ospeed = p->speed;
    730 		ttioctl(tp, TIOCSETAF, (caddr_t)&tt, 0, curproc);
    731 	}
    732 
    733 	sc->sc_ebofs = p->ebofs;
    734 	if (sc->sc_maxsize != p->maxsize) {
    735 		sc->sc_maxsize = p->maxsize;
    736 		if (sc->sc_inbuf != NULL)
    737 			free(sc->sc_inbuf, M_DEVBUF);
    738 		for (i = 0; i < MAXFRAMES; i++)
    739 			if (sc->sc_frames[i].buf != NULL)
    740 				free(sc->sc_frames[i].buf, M_DEVBUF);
    741 		if (sc->sc_maxsize != 0) {
    742 			sc->sc_inbuf = malloc(sc->sc_maxsize+2, M_DEVBUF,
    743 					      M_WAITOK);
    744 			for (i = 0; i < MAXFRAMES; i++)
    745 				sc->sc_frames[i].buf = malloc(sc->sc_maxsize,
    746 							   M_DEVBUF, M_WAITOK);
    747 		} else {
    748 			sc->sc_inbuf = NULL;
    749 			for (i = 0; i < MAXFRAMES; i++)
    750 				sc->sc_frames[i].buf = NULL;
    751 		}
    752 	}
    753 	sc->sc_framestate = FRAME_OUTSIDE;
    754 
    755 	return (0);
    756 }
    757 
    758 int
    759 irframet_get_speeds(void *h, int *speeds)
    760 {
    761 	struct tty *tp = h;
    762 
    763 	tp = tp;
    764 	DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
    765 	*speeds = IRDA_SPEEDS_SIR;
    766 	return (0);
    767 }
    768 
    769 int
    770 irframet_get_turnarounds(void *h, int *turnarounds)
    771 {
    772 	struct tty *tp = h;
    773 
    774 	tp = tp;
    775 	DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
    776 	*turnarounds = IRDA_TURNT_10000;
    777 	return (0);
    778 }
    779