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