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