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