1 /* $NetBSD: irframe_tty.c,v 1.20 2002/03/17 19:40:58 atatat 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 int error; 741 dev_t dev; 742 743 dev = tp->t_dev; 744 error = cdevsw[major(dev)].d_ioctl(dev, cmd, arg, 0, curproc); 745 #ifdef DIAGNOSTIC 746 if (error) 747 printf("irt_ioctl: cmd=0x%08lx error=%d\n", cmd, error); 748 #endif 749 } 750 751 void 752 irt_setspeed(struct tty *tp, u_int speed) 753 { 754 struct termios tt; 755 756 irt_ioctl(tp, TIOCGETA, &tt); 757 tt.c_ispeed = tt.c_ospeed = speed; 758 tt.c_cflag &= ~HUPCL; 759 tt.c_cflag |= CLOCAL; 760 irt_ioctl(tp, TIOCSETAF, &tt); 761 } 762 763 void 764 irt_setline(struct tty *tp, u_int line) 765 { 766 int mline; 767 768 irt_ioctl(tp, TIOCMGET, &mline); 769 mline &= ~(TIOCM_DTR | TIOCM_RTS); 770 mline |= line; 771 irt_ioctl(tp, TIOCMSET, (caddr_t)&mline); 772 } 773 774 void 775 irt_delay(struct tty *tp, u_int ms) 776 { 777 if (cold) 778 delay(ms * 1000); 779 else 780 tsleep(&irt_delay, PZERO, "irtdly", ms * hz / 1000 + 1); 781 782 } 783 784 /********************************************************************** 785 * No dongle 786 **********************************************************************/ 787 void 788 irts_none(struct tty *tp, u_int speed) 789 { 790 irt_setspeed(tp, speed); 791 } 792 793 /********************************************************************** 794 * Tekram 795 **********************************************************************/ 796 #define TEKRAM_PW 0x10 797 798 #define TEKRAM_115200 (TEKRAM_PW|0x00) 799 #define TEKRAM_57600 (TEKRAM_PW|0x01) 800 #define TEKRAM_38400 (TEKRAM_PW|0x02) 801 #define TEKRAM_19200 (TEKRAM_PW|0x03) 802 #define TEKRAM_9600 (TEKRAM_PW|0x04) 803 #define TEKRAM_2400 (TEKRAM_PW|0x08) 804 805 #define TEKRAM_TV (TEKRAM_PW|0x05) 806 807 void 808 irts_tekram(struct tty *tp, u_int speed) 809 { 810 int s; 811 812 irt_setspeed(tp, 9600); 813 irt_setline(tp, 0); 814 irt_delay(tp, 50); 815 816 irt_setline(tp, TIOCM_RTS); 817 irt_delay(tp, 1); 818 819 irt_setline(tp, TIOCM_DTR | TIOCM_RTS); 820 irt_delay(tp, 1); /* 50 us */ 821 822 irt_setline(tp, TIOCM_DTR); 823 irt_delay(tp, 1); /* 7 us */ 824 825 switch(speed) { 826 case 115200: s = TEKRAM_115200; break; 827 case 57600: s = TEKRAM_57600; break; 828 case 38400: s = TEKRAM_38400; break; 829 case 19200: s = TEKRAM_19200; break; 830 case 2400: s = TEKRAM_2400; break; 831 default: s = TEKRAM_9600; break; 832 } 833 irt_putc(tp, s); 834 irframetstart(tp); 835 836 irt_delay(tp, 100); 837 838 irt_setline(tp, TIOCM_DTR | TIOCM_RTS); 839 if (speed != 9600) 840 irt_setspeed(tp, speed); 841 irt_delay(tp, 1); /* 50 us */ 842 } 843 844 /********************************************************************** 845 * Jeteye 846 **********************************************************************/ 847 void 848 irts_jeteye(struct tty *tp, u_int speed) 849 { 850 switch (speed) { 851 case 19200: 852 irt_setline(tp, TIOCM_DTR); 853 break; 854 case 115200: 855 irt_setline(tp, TIOCM_DTR | TIOCM_RTS); 856 break; 857 default: /*9600*/ 858 irt_setline(tp, TIOCM_RTS); 859 break; 860 } 861 irt_setspeed(tp, speed); 862 } 863 864 /********************************************************************** 865 * Actisys 866 **********************************************************************/ 867 void 868 irts_actisys(struct tty *tp, u_int speed) 869 { 870 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc; 871 int pulses; 872 873 irt_setspeed(tp, speed); 874 875 switch(speed) { 876 case 19200: pulses=1; break; 877 case 57600: pulses=2; break; 878 case 115200: pulses=3; break; 879 case 38400: pulses=4; break; 880 default: /* 9600 */ pulses=0; break; 881 } 882 883 if (sc->sc_dongle_private == 0) { 884 sc->sc_dongle_private = 1; 885 irt_setline(tp, TIOCM_DTR | TIOCM_RTS); 886 /* 887 * Must wait at least 50ms after initial 888 * power on to charge internal capacitor 889 */ 890 irt_delay(tp, 50); 891 } 892 irt_setline(tp, TIOCM_RTS); 893 delay(2); 894 for (;;) { 895 irt_setline(tp, TIOCM_DTR | TIOCM_RTS); 896 delay(2); 897 if (--pulses <= 0) 898 break; 899 irt_setline(tp, TIOCM_DTR); 900 delay(2); 901 } 902 } 903 904 /********************************************************************** 905 * Litelink 906 **********************************************************************/ 907 void 908 irts_litelink(struct tty *tp, u_int speed) 909 { 910 struct irframet_softc *sc = (struct irframet_softc *)tp->t_sc; 911 int pulses; 912 913 irt_setspeed(tp, speed); 914 915 switch(speed) { 916 case 57600: pulses=1; break; 917 case 38400: pulses=2; break; 918 case 19200: pulses=3; break; 919 case 9600: pulses=4; break; 920 default: /* 115200 */ pulses=0; break; 921 } 922 923 if (sc->sc_dongle_private == 0) { 924 sc->sc_dongle_private = 1; 925 irt_setline(tp, TIOCM_DTR | TIOCM_RTS); 926 } 927 irt_setline(tp, TIOCM_RTS); 928 irt_delay(tp, 1); /* 15 us */; 929 for (;;) { 930 irt_setline(tp, TIOCM_DTR | TIOCM_RTS); 931 irt_delay(tp, 1); /* 15 us */; 932 if (--pulses <= 0) 933 break; 934 irt_setline(tp, TIOCM_DTR); 935 irt_delay(tp, 1); /* 15 us */; 936 } 937 } 938 939 /********************************************************************** 940 * Girbil 941 **********************************************************************/ 942 /* Control register 1 */ 943 #define GIRBIL_TXEN 0x01 /* Enable transmitter */ 944 #define GIRBIL_RXEN 0x02 /* Enable receiver */ 945 #define GIRBIL_ECAN 0x04 /* Cancel self emmited data */ 946 #define GIRBIL_ECHO 0x08 /* Echo control characters */ 947 948 /* LED Current Register */ 949 #define GIRBIL_HIGH 0x20 950 #define GIRBIL_MEDIUM 0x21 951 #define GIRBIL_LOW 0x22 952 953 /* Baud register */ 954 #define GIRBIL_2400 0x30 955 #define GIRBIL_4800 0x31 956 #define GIRBIL_9600 0x32 957 #define GIRBIL_19200 0x33 958 #define GIRBIL_38400 0x34 959 #define GIRBIL_57600 0x35 960 #define GIRBIL_115200 0x36 961 962 /* Mode register */ 963 #define GIRBIL_IRDA 0x40 964 #define GIRBIL_ASK 0x41 965 966 /* Control register 2 */ 967 #define GIRBIL_LOAD 0x51 /* Load the new baud rate value */ 968 969 void 970 irts_girbil(struct tty *tp, u_int speed) 971 { 972 int s; 973 974 irt_setspeed(tp, 9600); 975 irt_setline(tp, TIOCM_DTR); 976 irt_delay(tp, 5); 977 irt_setline(tp, TIOCM_RTS); 978 irt_delay(tp, 20); 979 switch(speed) { 980 case 115200: s = GIRBIL_115200; break; 981 case 57600: s = GIRBIL_57600; break; 982 case 38400: s = GIRBIL_38400; break; 983 case 19200: s = GIRBIL_19200; break; 984 case 4800: s = GIRBIL_4800; break; 985 case 2400: s = GIRBIL_2400; break; 986 default: s = GIRBIL_9600; break; 987 } 988 irt_putc(tp, GIRBIL_TXEN|GIRBIL_RXEN); 989 irt_putc(tp, s); 990 irt_putc(tp, GIRBIL_LOAD); 991 irframetstart(tp); 992 irt_delay(tp, 100); 993 irt_setline(tp, TIOCM_DTR | TIOCM_RTS); 994 if (speed != 9600) 995 irt_setspeed(tp, speed); 996 } 997