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