Home | History | Annotate | Line # | Download | only in ir
irframe_tty.c revision 1.33
      1 /*	$NetBSD: irframe_tty.c,v 1.33 2006/03/28 17:38:33 thorpej Exp $	*/
      2 
      3 /*
      4  * TODO
      5  *  Test dongle code.
      6  */
      7 
      8 /*
      9  * Copyright (c) 2001 The NetBSD Foundation, Inc.
     10  * All rights reserved.
     11  *
     12  * This code is derived from software contributed to The NetBSD Foundation
     13  * by Lennart Augustsson (lennart (at) augustsson.net) and Tommy Bohlin
     14  * (tommy (at) gatespace.com).
     15  *
     16  * Redistribution and use in source and binary forms, with or without
     17  * modification, are permitted provided that the following conditions
     18  * are met:
     19  * 1. Redistributions of source code must retain the above copyright
     20  *    notice, this list of conditions and the following disclaimer.
     21  * 2. Redistributions in binary form must reproduce the above copyright
     22  *    notice, this list of conditions and the following disclaimer in the
     23  *    documentation and/or other materials provided with the distribution.
     24  * 3. All advertising materials mentioning features or use of this software
     25  *    must display the following acknowledgement:
     26  *        This product includes software developed by the NetBSD
     27  *        Foundation, Inc. and its contributors.
     28  * 4. Neither the name of The NetBSD Foundation nor the names of its
     29  *    contributors may be used to endorse or promote products derived
     30  *    from this software without specific prior written permission.
     31  *
     32  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     33  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     34  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     35  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     36  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     37  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     38  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     39  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     40  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     41  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     42  * POSSIBILITY OF SUCH DAMAGE.
     43  */
     44 
     45 /*
     46  * Loosely based on ppp_tty.c.
     47  * Framing and dongle handling written by Tommy Bohlin.
     48  */
     49 
     50 #include <sys/cdefs.h>
     51 __KERNEL_RCSID(0, "$NetBSD: irframe_tty.c,v 1.33 2006/03/28 17:38:33 thorpej Exp $");
     52 
     53 #include <sys/param.h>
     54 #include <sys/proc.h>
     55 #include <sys/ioctl.h>
     56 #include <sys/tty.h>
     57 #include <sys/kernel.h>
     58 #include <sys/lock.h>
     59 #include <sys/malloc.h>
     60 #include <sys/conf.h>
     61 #include <sys/systm.h>
     62 #include <sys/device.h>
     63 #include <sys/file.h>
     64 #include <sys/vnode.h>
     65 #include <sys/poll.h>
     66 
     67 #include <dev/ir/ir.h>
     68 #include <dev/ir/sir.h>
     69 #include <dev/ir/irdaio.h>
     70 #include <dev/ir/irframevar.h>
     71 
     72 #ifdef IRFRAMET_DEBUG
     73 #define DPRINTF(x)	if (irframetdebug) printf x
     74 int irframetdebug = 0;
     75 #else
     76 #define DPRINTF(x)
     77 #endif
     78 
     79 /*****/
     80 
     81 /* Max size with framing. */
     82 #define MAX_IRDA_FRAME (2*IRDA_MAX_FRAME_SIZE + IRDA_MAX_EBOFS + 4)
     83 
     84 struct irt_frame {
     85 	u_char *buf;
     86 	u_int len;
     87 };
     88 #define MAXFRAMES 8
     89 
     90 struct irframet_softc {
     91 	struct irframe_softc sc_irp;
     92 	struct tty *sc_tp;
     93 
     94 	int sc_dongle;
     95 	int sc_dongle_private;
     96 
     97 	int sc_state;
     98 #define	IRT_RSLP		0x01	/* waiting for data (read) */
     99 #if 0
    100 #define	IRT_WSLP		0x02	/* waiting for data (write) */
    101 #define IRT_CLOSING		0x04	/* waiting for output to drain */
    102 #endif
    103 	struct lock sc_wr_lk;
    104 
    105 	struct irda_params sc_params;
    106 
    107 	u_char* sc_inbuf;
    108 	int sc_framestate;
    109 #define FRAME_OUTSIDE    0
    110 #define FRAME_INSIDE     1
    111 #define FRAME_ESCAPE     2
    112 	int sc_inchars;
    113 	int sc_inFCS;
    114 	struct callout sc_timeout;
    115 
    116 	u_int sc_nframes;
    117 	u_int sc_framei;
    118 	u_int sc_frameo;
    119 	struct irt_frame sc_frames[MAXFRAMES];
    120 	struct selinfo sc_rsel;
    121 	/* XXXJRT Nothing selnotify's sc_wsel */
    122 	struct selinfo sc_wsel;
    123 };
    124 
    125 /* line discipline methods */
    126 int	irframetopen(dev_t, struct tty *);
    127 int	irframetclose(struct tty *, int);
    128 int	irframetioctl(struct tty *, u_long, caddr_t, int, struct lwp *);
    129 int	irframetinput(int, struct tty *);
    130 int	irframetstart(struct tty *);
    131 
    132 /* pseudo device init */
    133 void	irframettyattach(int);
    134 
    135 /* irframe methods */
    136 static int	irframet_open(void *, int, int, struct lwp *);
    137 static int	irframet_close(void *, int, int, struct lwp *);
    138 static int	irframet_read(void *, struct uio *, int);
    139 static int	irframet_write(void *, struct uio *, int);
    140 static int	irframet_poll(void *, int, struct lwp *);
    141 static int	irframet_kqfilter(void *, struct knote *);
    142 
    143 static int	irframet_set_params(void *, struct irda_params *);
    144 static int	irframet_get_speeds(void *, int *);
    145 static int	irframet_get_turnarounds(void *, int *);
    146 
    147 /* internal */
    148 static int	irt_write_frame(struct tty *, u_int8_t *, size_t);
    149 static int	irt_putc(struct tty *, int);
    150 static void	irt_frame(struct irframet_softc *, u_char *, u_int);
    151 static void	irt_timeout(void *);
    152 static void	irt_ioctl(struct tty *, u_long, void *);
    153 static void	irt_setspeed(struct tty *, u_int);
    154 static void	irt_setline(struct tty *, u_int);
    155 static void	irt_delay(struct tty *, u_int);
    156 
    157 static const struct irframe_methods irframet_methods = {
    158 	irframet_open, irframet_close, irframet_read, irframet_write,
    159 	irframet_poll, irframet_kqfilter, irframet_set_params,
    160 	irframet_get_speeds, irframet_get_turnarounds
    161 };
    162 
    163 static void irts_none(struct tty *, u_int);
    164 static void irts_tekram(struct tty *, u_int);
    165 static void irts_jeteye(struct tty *, u_int);
    166 static void irts_actisys(struct tty *, u_int);
    167 static void irts_litelink(struct tty *, u_int);
    168 static void irts_girbil(struct tty *, u_int);
    169 
    170 #define NORMAL_SPEEDS (IRDA_SPEEDS_SIR & ~IRDA_SPEED_2400)
    171 #define TURNT_POS (IRDA_TURNT_10000 | IRDA_TURNT_5000 | IRDA_TURNT_1000 | \
    172 	IRDA_TURNT_500 | IRDA_TURNT_100 | IRDA_TURNT_50 | IRDA_TURNT_10)
    173 static const struct dongle {
    174 	void (*setspeed)(struct tty *, u_int);
    175 	u_int speedmask;
    176 	u_int turnmask;
    177 } irt_dongles[DONGLE_MAX] = {
    178 	/* Indexed by dongle number from irdaio.h */
    179 	{ irts_none, IRDA_SPEEDS_SIR, IRDA_TURNT_10000 },
    180 	{ irts_tekram, IRDA_SPEEDS_SIR, IRDA_TURNT_10000 },
    181 	{ irts_jeteye, IRDA_SPEED_9600|IRDA_SPEED_19200|IRDA_SPEED_115200,
    182 	  				IRDA_TURNT_10000 },
    183 	{ irts_actisys, NORMAL_SPEEDS & ~IRDA_SPEED_38400, TURNT_POS },
    184 	{ irts_actisys, NORMAL_SPEEDS, TURNT_POS },
    185 	{ irts_litelink, NORMAL_SPEEDS, TURNT_POS },
    186 	{ irts_girbil, IRDA_SPEEDS_SIR, IRDA_TURNT_10000 | IRDA_TURNT_5000 },
    187 };
    188 
    189 static struct linesw irframet_disc = {
    190 	.l_name = "irframe",
    191 	.l_open = irframetopen,
    192 	.l_close = irframetclose,
    193 	.l_read = ttyerrio,
    194 	.l_write = ttyerrio,
    195 	.l_ioctl = irframetioctl,
    196 	.l_rint = irframetinput,
    197 	.l_start = irframetstart,
    198 	.l_modem = ttymodem,
    199 	.l_poll = ttyerrpoll
    200 };
    201 
    202 void
    203 irframettyattach(int n)
    204 {
    205 
    206 	(void) ttyldisc_attach(&irframet_disc);
    207 }
    208 
    209 /*
    210  * Line specific open routine for async tty devices.
    211  * Attach the given tty to the first available irframe unit.
    212  * Called from device open routine or ttioctl.
    213  */
    214 /* ARGSUSED */
    215 int
    216 irframetopen(dev_t dev, struct tty *tp)
    217 {
    218 	struct lwp *l = curlwp;		/* XXX */
    219 	struct irframet_softc *sc;
    220 	struct proc *p;
    221 	int error, s;
    222 
    223 	p = l->l_proc;
    224 	DPRINTF(("%s\n", __FUNCTION__));
    225 
    226 	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
    227 		return (error);
    228 
    229 	s = spltty();
    230 
    231 	DPRINTF(("%s: linesw=%p disc=%s\n", __FUNCTION__, tp->t_linesw,
    232 		 tp->t_linesw->l_name));
    233 	if (tp->t_linesw == &irframet_disc) {
    234 		sc = (struct irframet_softc *)tp->t_sc;
    235 		DPRINTF(("%s: sc=%p sc_tp=%p\n", __FUNCTION__, sc, sc->sc_tp));
    236 		if (sc != NULL) {
    237 			splx(s);
    238 			return (EBUSY);
    239 		}
    240 	}
    241 
    242 	tp->t_sc = irframe_alloc(sizeof (struct irframet_softc),
    243 			&irframet_methods, tp);
    244 	sc = (struct irframet_softc *)tp->t_sc;
    245 	sc->sc_tp = tp;
    246 	printf("%s attached at tty%02d\n", sc->sc_irp.sc_dev.dv_xname,
    247 	    minor(tp->t_dev));
    248 
    249 	DPRINTF(("%s: set sc=%p\n", __FUNCTION__, sc));
    250 
    251 	ttyflush(tp, FREAD | FWRITE);
    252 
    253 	sc->sc_dongle = DONGLE_NONE;
    254 	sc->sc_dongle_private = 0;
    255 
    256 	splx(s);
    257 
    258 	return (0);
    259 }
    260 
    261 /*
    262  * Line specific close routine, called from device close routine
    263  * and from ttioctl.
    264  * Detach the tty from the irframe unit.
    265  * Mimics part of ttyclose().
    266  */
    267 int
    268 irframetclose(struct tty *tp, int flag)
    269 {
    270 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    271 	int s;
    272 
    273 	DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
    274 
    275 	s = spltty();
    276 	ttyflush(tp, FREAD | FWRITE);
    277 	ttyldisc_release(tp->t_linesw);
    278 	tp->t_linesw = ttyldisc_default();
    279 	if (sc != NULL) {
    280 		tp->t_sc = NULL;
    281 		printf("%s detached from tty%02d\n", sc->sc_irp.sc_dev.dv_xname,
    282 		    minor(tp->t_dev));
    283 
    284 		if (sc->sc_tp == tp)
    285 			irframe_dealloc(&sc->sc_irp.sc_dev);
    286 	}
    287 	splx(s);
    288 	return (0);
    289 }
    290 
    291 /*
    292  * Line specific (tty) ioctl routine.
    293  * This discipline requires that tty device drivers call
    294  * the line specific l_ioctl routine from their ioctl routines.
    295  */
    296 /* ARGSUSED */
    297 int
    298 irframetioctl(struct tty *tp, u_long cmd, caddr_t data, int flag,
    299 	     struct lwp *l)
    300 {
    301 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    302 	int error;
    303 	int d;
    304 
    305 	DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
    306 
    307 	if (sc == NULL || tp != sc->sc_tp)
    308 		return (EPASSTHROUGH);
    309 
    310 	error = 0;
    311 	switch (cmd) {
    312 	case IRFRAMETTY_GET_DEVICE:
    313 		*(int *)data = device_unit(&sc->sc_irp.sc_dev);
    314 		break;
    315 	case IRFRAMETTY_GET_DONGLE:
    316 		*(int *)data = sc->sc_dongle;
    317 		break;
    318 	case IRFRAMETTY_SET_DONGLE:
    319 		d = *(int *)data;
    320 		if (d < 0 || d >= DONGLE_MAX)
    321 			return (EINVAL);
    322 		sc->sc_dongle = d;
    323 		break;
    324 	default:
    325 		error = EPASSTHROUGH;
    326 		break;
    327 	}
    328 
    329 	return (error);
    330 }
    331 
    332 /*
    333  * Start output on async tty interface.
    334  */
    335 int
    336 irframetstart(struct tty *tp)
    337 {
    338 	/*struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;*/
    339 	int s;
    340 
    341 	DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
    342 
    343 	s = spltty();
    344 	if (tp->t_oproc != NULL)
    345 		(*tp->t_oproc)(tp);
    346 	splx(s);
    347 
    348 	return (0);
    349 }
    350 
    351 void
    352 irt_frame(struct irframet_softc *sc, u_char *tbuf, u_int len)
    353 {
    354 	DPRINTF(("%s: nframe=%d framei=%d frameo=%d\n",
    355 		 __FUNCTION__, sc->sc_nframes, sc->sc_framei, sc->sc_frameo));
    356 
    357 	if (sc->sc_inbuf == NULL) /* XXX happens if device is closed? */
    358 		return;
    359 	if (sc->sc_nframes >= MAXFRAMES) {
    360 #ifdef IRFRAMET_DEBUG
    361 		printf("%s: dropped frame\n", __FUNCTION__);
    362 #endif
    363 		return;
    364 	}
    365 	if (sc->sc_frames[sc->sc_framei].buf == NULL)
    366 		return;
    367 	memcpy(sc->sc_frames[sc->sc_framei].buf, tbuf, len);
    368 	sc->sc_frames[sc->sc_framei].len = len;
    369 	sc->sc_framei = (sc->sc_framei+1) % MAXFRAMES;
    370 	sc->sc_nframes++;
    371 	if (sc->sc_state & IRT_RSLP) {
    372 		sc->sc_state &= ~IRT_RSLP;
    373 		DPRINTF(("%s: waking up reader\n", __FUNCTION__));
    374 		wakeup(sc->sc_frames);
    375 	}
    376 	selnotify(&sc->sc_rsel, 0);
    377 }
    378 
    379 void
    380 irt_timeout(void *v)
    381 {
    382 	struct irframet_softc *sc = v;
    383 
    384 #ifdef IRFRAMET_DEBUG
    385 	if (sc->sc_framestate != FRAME_OUTSIDE)
    386 		printf("%s: input frame timeout\n", __FUNCTION__);
    387 #endif
    388 	sc->sc_framestate = FRAME_OUTSIDE;
    389 }
    390 
    391 int
    392 irframetinput(int c, struct tty *tp)
    393 {
    394 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    395 
    396 	c &= 0xff;
    397 
    398 #if IRFRAMET_DEBUG
    399 	if (irframetdebug > 1)
    400 		DPRINTF(("%s: tp=%p c=0x%02x\n", __FUNCTION__, tp, c));
    401 #endif
    402 
    403 	if (sc == NULL || tp != (struct tty *)sc->sc_tp)
    404 		return (0);
    405 
    406 	if (sc->sc_inbuf == NULL)
    407 		return (0);
    408 
    409 	switch (c) {
    410 	case SIR_BOF:
    411 		DPRINTF(("%s: BOF\n", __FUNCTION__));
    412 		sc->sc_framestate = FRAME_INSIDE;
    413 		sc->sc_inchars = 0;
    414 		sc->sc_inFCS = INITFCS;
    415 		break;
    416 	case SIR_EOF:
    417 		DPRINTF(("%s: EOF state=%d inchars=%d fcs=0x%04x\n",
    418 			 __FUNCTION__,
    419 			 sc->sc_framestate, sc->sc_inchars, sc->sc_inFCS));
    420 		if (sc->sc_framestate == FRAME_INSIDE &&
    421 		    sc->sc_inchars >= 4 && sc->sc_inFCS == GOODFCS) {
    422 			irt_frame(sc, sc->sc_inbuf, sc->sc_inchars - 2);
    423 		} else if (sc->sc_framestate != FRAME_OUTSIDE) {
    424 #ifdef IRFRAMET_DEBUG
    425 			printf("%s: malformed input frame\n", __FUNCTION__);
    426 #endif
    427 		}
    428 		sc->sc_framestate = FRAME_OUTSIDE;
    429 		break;
    430 	case SIR_CE:
    431 		DPRINTF(("%s: CE\n", __FUNCTION__));
    432 		if (sc->sc_framestate == FRAME_INSIDE)
    433 			sc->sc_framestate = FRAME_ESCAPE;
    434 		break;
    435 	default:
    436 #if IRFRAMET_DEBUG
    437 	if (irframetdebug > 1)
    438 		DPRINTF(("%s: c=0x%02x, inchar=%d state=%d\n", __FUNCTION__, c,
    439 			 sc->sc_inchars, sc->sc_state));
    440 #endif
    441 		if (sc->sc_framestate != FRAME_OUTSIDE) {
    442 			if (sc->sc_framestate == FRAME_ESCAPE) {
    443 				sc->sc_framestate = FRAME_INSIDE;
    444 				c ^= SIR_ESC_BIT;
    445 			}
    446 			if (sc->sc_inchars < sc->sc_params.maxsize + 2) {
    447 				sc->sc_inbuf[sc->sc_inchars++] = c;
    448 				sc->sc_inFCS = updateFCS(sc->sc_inFCS, c);
    449 			} else {
    450 				sc->sc_framestate = FRAME_OUTSIDE;
    451 #ifdef IRFRAMET_DEBUG
    452 				printf("%s: input frame overrun\n",
    453 				       __FUNCTION__);
    454 #endif
    455 			}
    456 		}
    457 		break;
    458 	}
    459 
    460 #if 1
    461 	if (sc->sc_framestate != FRAME_OUTSIDE) {
    462 		callout_reset(&sc->sc_timeout, hz/20, irt_timeout, sc);
    463 	}
    464 #endif
    465 
    466 	return (0);
    467 }
    468 
    469 
    470 /*** irframe methods ***/
    471 
    472 int
    473 irframet_open(void *h, int flag, int mode, struct lwp *l)
    474 {
    475 	struct tty *tp = h;
    476 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    477 
    478 	DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
    479 
    480 	sc->sc_params.speed = 0;
    481 	sc->sc_params.ebofs = IRDA_DEFAULT_EBOFS;
    482 	sc->sc_params.maxsize = 0;
    483 	sc->sc_framestate = FRAME_OUTSIDE;
    484 	sc->sc_nframes = 0;
    485 	sc->sc_framei = 0;
    486 	sc->sc_frameo = 0;
    487 	callout_init(&sc->sc_timeout);
    488 	lockinit(&sc->sc_wr_lk, PZERO, "irfrtl", 0, 0);
    489 
    490 	return (0);
    491 }
    492 
    493 int
    494 irframet_close(void *h, int flag, int mode, struct lwp *l)
    495 {
    496 	struct tty *tp = h;
    497 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    498 	int i, s;
    499 
    500 	DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
    501 
    502 	callout_stop(&sc->sc_timeout);
    503 	s = splir();
    504 	if (sc->sc_inbuf != NULL) {
    505 		free(sc->sc_inbuf, M_DEVBUF);
    506 		sc->sc_inbuf = NULL;
    507 	}
    508 	for (i = 0; i < MAXFRAMES; i++) {
    509 		if (sc->sc_frames[i].buf != NULL) {
    510 			free(sc->sc_frames[i].buf, M_DEVBUF);
    511 			sc->sc_frames[i].buf = NULL;
    512 		}
    513 	}
    514 	splx(s);
    515 
    516 	return (0);
    517 }
    518 
    519 int
    520 irframet_read(void *h, struct uio *uio, int flag)
    521 {
    522 	struct tty *tp = h;
    523 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    524 	int error = 0;
    525 	int s;
    526 
    527 	DPRINTF(("%s: resid=%d, iovcnt=%d, offset=%ld\n",
    528 		 __FUNCTION__, uio->uio_resid, uio->uio_iovcnt,
    529 		 (long)uio->uio_offset));
    530 	DPRINTF(("%s: nframe=%d framei=%d frameo=%d\n",
    531 		 __FUNCTION__, sc->sc_nframes, sc->sc_framei, sc->sc_frameo));
    532 
    533 
    534 	s = splir();
    535 	while (sc->sc_nframes == 0) {
    536 		if (flag & IO_NDELAY) {
    537 			splx(s);
    538 			return (EWOULDBLOCK);
    539 		}
    540 		sc->sc_state |= IRT_RSLP;
    541 		DPRINTF(("%s: sleep\n", __FUNCTION__));
    542 		error = tsleep(sc->sc_frames, PZERO | PCATCH, "irtrd", 0);
    543 		DPRINTF(("%s: woke, error=%d\n", __FUNCTION__, error));
    544 		if (error) {
    545 			sc->sc_state &= ~IRT_RSLP;
    546 			break;
    547 		}
    548 	}
    549 
    550 	/* Do just one frame transfer per read */
    551 	if (!error) {
    552 		if (uio->uio_resid < sc->sc_frames[sc->sc_frameo].len) {
    553 			DPRINTF(("%s: uio buffer smaller than frame size "
    554 				 "(%d < %d)\n", __FUNCTION__, uio->uio_resid,
    555 				 sc->sc_frames[sc->sc_frameo].len));
    556 			error = EINVAL;
    557 		} else {
    558 			DPRINTF(("%s: moving %d bytes\n", __FUNCTION__,
    559 				 sc->sc_frames[sc->sc_frameo].len));
    560 			error = uiomove(sc->sc_frames[sc->sc_frameo].buf,
    561 					sc->sc_frames[sc->sc_frameo].len, uio);
    562 			DPRINTF(("%s: error=%d\n", __FUNCTION__, error));
    563 		}
    564 		sc->sc_frameo = (sc->sc_frameo+1) % MAXFRAMES;
    565 		sc->sc_nframes--;
    566 	}
    567 	splx(s);
    568 
    569 	return (error);
    570 }
    571 
    572 int
    573 irt_putc(struct tty *tp, int c)
    574 {
    575 	int s;
    576 	int error;
    577 
    578 #if IRFRAMET_DEBUG
    579 	if (irframetdebug > 3)
    580 		DPRINTF(("%s: tp=%p c=0x%02x cc=%d\n", __FUNCTION__, tp, c,
    581 			 tp->t_outq.c_cc));
    582 #endif
    583 	if (tp->t_outq.c_cc > tp->t_hiwat) {
    584 		irframetstart(tp);
    585 		s = spltty();
    586 		/*
    587 		 * This can only occur if FLUSHO is set in t_lflag,
    588 		 * or if ttstart/oproc is synchronous (or very fast).
    589 		 */
    590 		if (tp->t_outq.c_cc <= tp->t_hiwat) {
    591 			splx(s);
    592 			goto go;
    593 		}
    594 		SET(tp->t_state, TS_ASLEEP);
    595 		error = ttysleep(tp, &tp->t_outq, TTOPRI | PCATCH, ttyout, 0);
    596 		splx(s);
    597 		if (error)
    598 			return (error);
    599 	}
    600  go:
    601 	if (putc(c, &tp->t_outq) < 0) {
    602 		printf("irframe: putc failed\n");
    603 		return (EIO);
    604 	}
    605 	return (0);
    606 }
    607 
    608 int
    609 irframet_write(void *h, struct uio *uio, int flag)
    610 {
    611 	struct tty *tp = h;
    612 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    613 	u_int8_t tbuf[MAX_IRDA_FRAME];
    614 	int n;
    615 
    616 	DPRINTF(("%s: resid=%d, iovcnt=%d, offset=%ld\n",
    617 		 __FUNCTION__, uio->uio_resid, uio->uio_iovcnt,
    618 		 (long)uio->uio_offset));
    619 
    620 	n = irda_sir_frame(tbuf, MAX_IRDA_FRAME, uio, sc->sc_params.ebofs);
    621 	if (n < 0) {
    622 #ifdef IRFRAMET_DEBUG
    623 		printf("%s: irda_sir_frame() error=%d\n", __FUNCTION__, -n);
    624 #endif
    625 		return (-n);
    626 	}
    627 	return (irt_write_frame(tp, tbuf, n));
    628 }
    629 
    630 int
    631 irt_write_frame(struct tty *tp, u_int8_t *tbuf, size_t len)
    632 {
    633 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    634 	int error, i;
    635 
    636 	DPRINTF(("%s: tp=%p len=%d\n", __FUNCTION__, tp, len));
    637 
    638 	lockmgr(&sc->sc_wr_lk, LK_EXCLUSIVE, NULL);
    639 	error = 0;
    640 	for (i = 0; !error && i < len; i++)
    641 		error = irt_putc(tp, tbuf[i]);
    642 	lockmgr(&sc->sc_wr_lk, LK_RELEASE, NULL);
    643 
    644 	irframetstart(tp);
    645 
    646 	DPRINTF(("%s: done, error=%d\n", __FUNCTION__, error));
    647 
    648 	return (error);
    649 }
    650 
    651 int
    652 irframet_poll(void *h, int events, struct lwp *l)
    653 {
    654 	struct tty *tp = h;
    655 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    656 	int revents = 0;
    657 	int s;
    658 
    659 	DPRINTF(("%s: sc=%p\n", __FUNCTION__, sc));
    660 
    661 	s = splir();
    662 	/* XXX is this a good check? */
    663 	if (events & (POLLOUT | POLLWRNORM))
    664 		if (tp->t_outq.c_cc <= tp->t_lowat)
    665 			revents |= events & (POLLOUT | POLLWRNORM);
    666 
    667 	if (events & (POLLIN | POLLRDNORM)) {
    668 		if (sc->sc_nframes > 0) {
    669 			DPRINTF(("%s: have data\n", __FUNCTION__));
    670 			revents |= events & (POLLIN | POLLRDNORM);
    671 		} else {
    672 			DPRINTF(("%s: recording select\n", __FUNCTION__));
    673 			selrecord(l, &sc->sc_rsel);
    674 		}
    675 	}
    676 	splx(s);
    677 
    678 	return (revents);
    679 }
    680 
    681 static void
    682 filt_irframetrdetach(struct knote *kn)
    683 {
    684 	struct tty *tp = kn->kn_hook;
    685 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    686 	int s;
    687 
    688 	s = splir();
    689 	SLIST_REMOVE(&sc->sc_rsel.sel_klist, kn, knote, kn_selnext);
    690 	splx(s);
    691 }
    692 
    693 static int
    694 filt_irframetread(struct knote *kn, long hint)
    695 {
    696 	struct tty *tp = kn->kn_hook;
    697 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    698 
    699 	kn->kn_data = sc->sc_nframes;
    700 	return (kn->kn_data > 0);
    701 }
    702 
    703 static void
    704 filt_irframetwdetach(struct knote *kn)
    705 {
    706 	struct tty *tp = kn->kn_hook;
    707 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    708 	int s;
    709 
    710 	s = splir();
    711 	SLIST_REMOVE(&sc->sc_wsel.sel_klist, kn, knote, kn_selnext);
    712 	splx(s);
    713 }
    714 
    715 static int
    716 filt_irframetwrite(struct knote *kn, long hint)
    717 {
    718 	struct tty *tp = kn->kn_hook;
    719 
    720 	/* XXX double-check this */
    721 
    722 	if (tp->t_outq.c_cc <= tp->t_lowat) {
    723 		kn->kn_data = tp->t_lowat - tp->t_outq.c_cc;
    724 		return (1);
    725 	}
    726 
    727 	kn->kn_data = 0;
    728 	return (0);
    729 }
    730 
    731 static const struct filterops irframetread_filtops =
    732 	{ 1, NULL, filt_irframetrdetach, filt_irframetread };
    733 static const struct filterops irframetwrite_filtops =
    734 	{ 1, NULL, filt_irframetwdetach, filt_irframetwrite };
    735 
    736 int
    737 irframet_kqfilter(void *h, struct knote *kn)
    738 {
    739 	struct tty *tp = h;
    740 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    741 	struct klist *klist;
    742 	int s;
    743 
    744 	switch (kn->kn_filter) {
    745 	case EVFILT_READ:
    746 		klist = &sc->sc_rsel.sel_klist;
    747 		kn->kn_fop = &irframetread_filtops;
    748 		break;
    749 	case EVFILT_WRITE:
    750 		klist = &sc->sc_wsel.sel_klist;
    751 		kn->kn_fop = &irframetwrite_filtops;
    752 		break;
    753 	default:
    754 		return (1);
    755 	}
    756 
    757 	kn->kn_hook = tp;
    758 
    759 	s = splir();
    760 	SLIST_INSERT_HEAD(klist, kn, kn_selnext);
    761 	splx(s);
    762 
    763 	return (0);
    764 }
    765 
    766 int
    767 irframet_set_params(void *h, struct irda_params *p)
    768 {
    769 	struct tty *tp = h;
    770 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    771 	int i;
    772 
    773 	DPRINTF(("%s: tp=%p speed=%d ebofs=%d maxsize=%d\n",
    774 		 __FUNCTION__, tp, p->speed, p->ebofs, p->maxsize));
    775 
    776 	if (p->speed != sc->sc_params.speed) {
    777 		/* Checked in irframe.c */
    778 		lockmgr(&sc->sc_wr_lk, LK_EXCLUSIVE, NULL);
    779 		irt_dongles[sc->sc_dongle].setspeed(tp, p->speed);
    780 		lockmgr(&sc->sc_wr_lk, LK_RELEASE, NULL);
    781 		sc->sc_params.speed = p->speed;
    782 	}
    783 
    784 	/* Max size checked in irframe.c */
    785 	sc->sc_params.ebofs = p->ebofs;
    786 	/* Max size checked in irframe.c */
    787 	if (sc->sc_params.maxsize != p->maxsize) {
    788 		sc->sc_params.maxsize = p->maxsize;
    789 		if (sc->sc_inbuf != NULL)
    790 			free(sc->sc_inbuf, M_DEVBUF);
    791 		for (i = 0; i < MAXFRAMES; i++)
    792 			if (sc->sc_frames[i].buf != NULL)
    793 				free(sc->sc_frames[i].buf, M_DEVBUF);
    794 		if (sc->sc_params.maxsize != 0) {
    795 			sc->sc_inbuf = malloc(sc->sc_params.maxsize+2,
    796 					      M_DEVBUF, M_WAITOK);
    797 			for (i = 0; i < MAXFRAMES; i++)
    798 				sc->sc_frames[i].buf =
    799 					malloc(sc->sc_params.maxsize,
    800 					       M_DEVBUF, M_WAITOK);
    801 		} else {
    802 			sc->sc_inbuf = NULL;
    803 			for (i = 0; i < MAXFRAMES; i++)
    804 				sc->sc_frames[i].buf = NULL;
    805 		}
    806 	}
    807 	sc->sc_framestate = FRAME_OUTSIDE;
    808 
    809 	return (0);
    810 }
    811 
    812 int
    813 irframet_get_speeds(void *h, int *speeds)
    814 {
    815 	struct tty *tp = h;
    816 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    817 
    818 	DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
    819 
    820 	if (sc == NULL)		/* during attach */
    821 		*speeds = IRDA_SPEEDS_SIR;
    822 	else
    823 		*speeds = irt_dongles[sc->sc_dongle].speedmask;
    824 	return (0);
    825 }
    826 
    827 int
    828 irframet_get_turnarounds(void *h, int *turnarounds)
    829 {
    830 	struct tty *tp = h;
    831 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    832 
    833 	DPRINTF(("%s: tp=%p\n", __FUNCTION__, tp));
    834 
    835 	*turnarounds = irt_dongles[sc->sc_dongle].turnmask;
    836 	return (0);
    837 }
    838 
    839 void
    840 irt_ioctl(struct tty *tp, u_long cmd, void *arg)
    841 {
    842 	const struct cdevsw *cdev;
    843 	int error;
    844 	dev_t dev;
    845 
    846 	dev = tp->t_dev;
    847 	cdev = cdevsw_lookup(dev);
    848 	if (cdev != NULL)
    849 		error = (*cdev->d_ioctl)(dev, cmd, arg, 0, curlwp);
    850 	else
    851 		error = ENXIO;
    852 #ifdef DIAGNOSTIC
    853 	if (error)
    854 		printf("irt_ioctl: cmd=0x%08lx error=%d\n", cmd, error);
    855 #endif
    856 }
    857 
    858 void
    859 irt_setspeed(struct tty *tp, u_int speed)
    860 {
    861 	struct termios tt;
    862 
    863 	irt_ioctl(tp, TIOCGETA,  &tt);
    864 	tt.c_ispeed = tt.c_ospeed = speed;
    865 	tt.c_cflag &= ~HUPCL;
    866 	tt.c_cflag |= CLOCAL;
    867 	irt_ioctl(tp, TIOCSETAF, &tt);
    868 }
    869 
    870 void
    871 irt_setline(struct tty *tp, u_int line)
    872 {
    873 	int mline;
    874 
    875 	irt_ioctl(tp, TIOCMGET, &mline);
    876 	mline &= ~(TIOCM_DTR | TIOCM_RTS);
    877 	mline |= line;
    878 	irt_ioctl(tp, TIOCMSET, (caddr_t)&mline);
    879 }
    880 
    881 void
    882 irt_delay(struct tty *tp, u_int ms)
    883 {
    884 	if (cold)
    885 		delay(ms * 1000);
    886 	else
    887 		tsleep(&irt_delay, PZERO, "irtdly", ms * hz / 1000 + 1);
    888 
    889 }
    890 
    891 /**********************************************************************
    892  * No dongle
    893  **********************************************************************/
    894 void
    895 irts_none(struct tty *tp, u_int speed)
    896 {
    897 	irt_setspeed(tp, speed);
    898 }
    899 
    900 /**********************************************************************
    901  * Tekram
    902  **********************************************************************/
    903 #define TEKRAM_PW     0x10
    904 
    905 #define TEKRAM_115200 (TEKRAM_PW|0x00)
    906 #define TEKRAM_57600  (TEKRAM_PW|0x01)
    907 #define TEKRAM_38400  (TEKRAM_PW|0x02)
    908 #define TEKRAM_19200  (TEKRAM_PW|0x03)
    909 #define TEKRAM_9600   (TEKRAM_PW|0x04)
    910 #define TEKRAM_2400   (TEKRAM_PW|0x08)
    911 
    912 #define TEKRAM_TV     (TEKRAM_PW|0x05)
    913 
    914 void
    915 irts_tekram(struct tty *tp, u_int speed)
    916 {
    917 	int s;
    918 
    919 	irt_setspeed(tp, 9600);
    920 	irt_setline(tp, 0);
    921 	irt_delay(tp, 50);
    922 
    923 	irt_setline(tp, TIOCM_RTS);
    924 	irt_delay(tp, 1);
    925 
    926 	irt_setline(tp, TIOCM_DTR | TIOCM_RTS);
    927 	irt_delay(tp, 1);	/* 50 us */
    928 
    929 	irt_setline(tp, TIOCM_DTR);
    930 	irt_delay(tp, 1);	/* 7 us */
    931 
    932 	switch(speed) {
    933 	case 115200: s = TEKRAM_115200; break;
    934 	case 57600:  s = TEKRAM_57600; break;
    935 	case 38400:  s = TEKRAM_38400; break;
    936 	case 19200:  s = TEKRAM_19200; break;
    937 	case 2400:   s = TEKRAM_2400; break;
    938 	default:     s = TEKRAM_9600; break;
    939 	}
    940 	irt_putc(tp, s);
    941 	irframetstart(tp);
    942 
    943 	irt_delay(tp, 100);
    944 
    945 	irt_setline(tp, TIOCM_DTR | TIOCM_RTS);
    946 	if (speed != 9600)
    947 		irt_setspeed(tp, speed);
    948 	irt_delay(tp, 1);	/* 50 us */
    949 }
    950 
    951 /**********************************************************************
    952  * Jeteye
    953  **********************************************************************/
    954 void
    955 irts_jeteye(struct tty *tp, u_int speed)
    956 {
    957 	switch (speed) {
    958 	case 19200:
    959 		irt_setline(tp, TIOCM_DTR);
    960 		break;
    961 	case 115200:
    962 		irt_setline(tp, TIOCM_DTR | TIOCM_RTS);
    963 		break;
    964 	default: /*9600*/
    965 		irt_setline(tp, TIOCM_RTS);
    966 		break;
    967 	}
    968 	irt_setspeed(tp, speed);
    969 }
    970 
    971 /**********************************************************************
    972  * Actisys
    973  **********************************************************************/
    974 void
    975 irts_actisys(struct tty *tp, u_int speed)
    976 {
    977 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
    978 	int pulses;
    979 
    980 	irt_setspeed(tp, speed);
    981 
    982 	switch(speed) {
    983 	case 19200:  pulses=1; break;
    984 	case 57600:  pulses=2; break;
    985 	case 115200: pulses=3; break;
    986 	case 38400:  pulses=4; break;
    987 	default: /* 9600 */ pulses=0; break;
    988 	}
    989 
    990 	if (sc->sc_dongle_private == 0) {
    991 		sc->sc_dongle_private = 1;
    992 		irt_setline(tp, TIOCM_DTR | TIOCM_RTS);
    993 		/*
    994 		 * Must wait at least 50ms after initial
    995 		 * power on to charge internal capacitor
    996 		 */
    997 		irt_delay(tp, 50);
    998 	}
    999 	irt_setline(tp, TIOCM_RTS);
   1000 	delay(2);
   1001 	for (;;) {
   1002 		irt_setline(tp, TIOCM_DTR | TIOCM_RTS);
   1003 		delay(2);
   1004 		if (--pulses <= 0)
   1005 			break;
   1006 		irt_setline(tp, TIOCM_DTR);
   1007 		delay(2);
   1008 	}
   1009 }
   1010 
   1011 /**********************************************************************
   1012  * Litelink
   1013  **********************************************************************/
   1014 void
   1015 irts_litelink(struct tty *tp, u_int speed)
   1016 {
   1017 	struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc;
   1018 	int pulses;
   1019 
   1020 	irt_setspeed(tp, speed);
   1021 
   1022 	switch(speed) {
   1023 	case 57600:  pulses=1; break;
   1024 	case 38400:  pulses=2; break;
   1025 	case 19200:  pulses=3; break;
   1026 	case 9600:   pulses=4; break;
   1027 	default: /* 115200 */ pulses=0; break;
   1028 	}
   1029 
   1030 	if (sc->sc_dongle_private == 0) {
   1031 		sc->sc_dongle_private = 1;
   1032 		irt_setline(tp, TIOCM_DTR | TIOCM_RTS);
   1033 	}
   1034 	irt_setline(tp, TIOCM_RTS);
   1035 	irt_delay(tp, 1); /* 15 us */;
   1036 	for (;;) {
   1037 		irt_setline(tp, TIOCM_DTR | TIOCM_RTS);
   1038 		irt_delay(tp, 1); /* 15 us */;
   1039 		if (--pulses <= 0)
   1040 			break;
   1041 		irt_setline(tp, TIOCM_DTR);
   1042 		irt_delay(tp, 1); /* 15 us */;
   1043 	}
   1044 }
   1045 
   1046 /**********************************************************************
   1047  * Girbil
   1048  **********************************************************************/
   1049 /* Control register 1 */
   1050 #define GIRBIL_TXEN      0x01 /* Enable transmitter */
   1051 #define GIRBIL_RXEN      0x02 /* Enable receiver */
   1052 #define GIRBIL_ECAN      0x04 /* Cancel self emmited data */
   1053 #define GIRBIL_ECHO      0x08 /* Echo control characters */
   1054 
   1055 /* LED Current Register */
   1056 #define GIRBIL_HIGH      0x20
   1057 #define GIRBIL_MEDIUM    0x21
   1058 #define GIRBIL_LOW       0x22
   1059 
   1060 /* Baud register */
   1061 #define GIRBIL_2400      0x30
   1062 #define GIRBIL_4800      0x31
   1063 #define GIRBIL_9600      0x32
   1064 #define GIRBIL_19200     0x33
   1065 #define GIRBIL_38400     0x34
   1066 #define GIRBIL_57600     0x35
   1067 #define GIRBIL_115200    0x36
   1068 
   1069 /* Mode register */
   1070 #define GIRBIL_IRDA      0x40
   1071 #define GIRBIL_ASK       0x41
   1072 
   1073 /* Control register 2 */
   1074 #define GIRBIL_LOAD      0x51 /* Load the new baud rate value */
   1075 
   1076 void
   1077 irts_girbil(struct tty *tp, u_int speed)
   1078 {
   1079 	int s;
   1080 
   1081 	irt_setspeed(tp, 9600);
   1082 	irt_setline(tp, TIOCM_DTR);
   1083 	irt_delay(tp, 5);
   1084 	irt_setline(tp, TIOCM_RTS);
   1085 	irt_delay(tp, 20);
   1086 	switch(speed) {
   1087 	case 115200: s = GIRBIL_115200; break;
   1088 	case 57600:  s = GIRBIL_57600; break;
   1089 	case 38400:  s = GIRBIL_38400; break;
   1090 	case 19200:  s = GIRBIL_19200; break;
   1091 	case 4800:   s = GIRBIL_4800; break;
   1092 	case 2400:   s = GIRBIL_2400; break;
   1093 	default:     s = GIRBIL_9600; break;
   1094 	}
   1095 	irt_putc(tp, GIRBIL_TXEN|GIRBIL_RXEN);
   1096 	irt_putc(tp, s);
   1097 	irt_putc(tp, GIRBIL_LOAD);
   1098 	irframetstart(tp);
   1099 	irt_delay(tp, 100);
   1100 	irt_setline(tp, TIOCM_DTR | TIOCM_RTS);
   1101 	if (speed != 9600)
   1102 		irt_setspeed(tp, speed);
   1103 }
   1104