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