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