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