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