|
|
1.1 ! root 1: /* ! 2: * Mach Operating System ! 3: * Copyright (c) 1993-1988 Carnegie Mellon University ! 4: * All Rights Reserved. ! 5: * ! 6: * Permission to use, copy, modify and distribute this software and its ! 7: * documentation is hereby granted, provided that both the copyright ! 8: * notice and this permission notice appear in all copies of the ! 9: * software, derivative works or modified versions, and any portions ! 10: * thereof, and that both notices appear in supporting documentation. ! 11: * ! 12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 15: * ! 16: * Carnegie Mellon requests users of this software to return to ! 17: * ! 18: * Software Distribution Coordinator or [email protected] ! 19: * School of Computer Science ! 20: * Carnegie Mellon University ! 21: * Pittsburgh PA 15213-3890 ! 22: * ! 23: * any improvements or extensions that they make and grant Carnegie Mellon ! 24: * the rights to redistribute these changes. ! 25: */ ! 26: /* ! 27: * Author: David B. Golub, Carnegie Mellon University ! 28: * Date: 8/88 ! 29: * ! 30: * TTY io. ! 31: * Compatibility with old TTY device drivers. ! 32: */ ! 33: ! 34: #include <mach/kern_return.h> ! 35: #include <mach/mig_errors.h> ! 36: #include <mach/vm_param.h> ! 37: #include <machine/machspl.h> /* spl definitions */ ! 38: ! 39: #include <ipc/ipc_port.h> ! 40: ! 41: #include <kern/lock.h> ! 42: #include <kern/queue.h> ! 43: ! 44: #include <vm/vm_map.h> ! 45: #include <vm/vm_kern.h> ! 46: ! 47: #include <device/device_types.h> ! 48: #include <device/io_req.h> ! 49: #include <device/ds_routines.h> ! 50: #include "device_reply.h" ! 51: ! 52: #include <device/tty.h> ! 53: ! 54: /* If you change these, check that tty_outq_size and tty_inq_size ! 55: * is greater than largest tthiwat entry. ! 56: */ ! 57: short tthiwat[16] = ! 58: { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,1300,2000 }; ! 59: short ttlowat[16] = ! 60: { 30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125, 125, 125 }; ! 61: ! 62: /* ! 63: * forward declarations ! 64: */ ! 65: void queue_delayed_reply( ! 66: queue_t, io_req_t, boolean_t (*)(io_req_t)); ! 67: void tty_output(struct tty *); ! 68: void tty_flush(struct tty *, int); ! 69: boolean_t char_open_done(io_req_t); ! 70: boolean_t char_read_done(io_req_t); ! 71: boolean_t char_write_done(io_req_t); ! 72: ! 73: /* ! 74: * Fake 'line discipline' switch for the benefit of old code ! 75: * that wants to call through it. ! 76: */ ! 77: struct ldisc_switch linesw[] = { ! 78: { ! 79: char_read, ! 80: char_write, ! 81: ttyinput, ! 82: ttymodem, ! 83: tty_output ! 84: } ! 85: }; ! 86: ! 87: /* ! 88: * Sizes for input and output circular buffers. ! 89: */ ! 90: int tty_inq_size = 4096; /* big nuf */ ! 91: int tty_outq_size = 2048; /* Must be bigger that tthiwat */ ! 92: int pdma_default = 1; /* turn pseudo dma on by default */ ! 93: ! 94: /* ! 95: * compute pseudo-dma tables ! 96: */ ! 97: ! 98: int pdma_timeouts[NSPEEDS]; /* how many ticks in timeout */ ! 99: int pdma_water_mark[NSPEEDS]; ! 100: ! 101: ! 102: void chario_init(void) ! 103: { ! 104: /* the basic idea with the timeouts is two allow enough ! 105: time for a character to show up if data is coming in at full data rate ! 106: plus a little slack. 2 ticks is considered slack ! 107: Below 300 baud we just glob a character at a time */ ! 108: #define _PR(x) ((hz/x) + 2) ! 109: ! 110: int i; ! 111: ! 112: for (i = B0; i < B300; i++) ! 113: pdma_timeouts[i] = 0; ! 114: ! 115: pdma_timeouts[B300] = _PR(30); ! 116: pdma_timeouts[B600] = _PR(60); ! 117: pdma_timeouts[B1200] = _PR(120); ! 118: pdma_timeouts[B1800] = _PR(180); ! 119: pdma_timeouts[B2400] = _PR(240); ! 120: pdma_timeouts[B4800] = _PR(480); ! 121: pdma_timeouts[B9600] = _PR(960); ! 122: pdma_timeouts[EXTA] = _PR(1440); /* >14400 baud */ ! 123: pdma_timeouts[EXTB] = _PR(1920); /* >19200 baud */ ! 124: ! 125: for (i = B0; i < B300; i++) ! 126: pdma_water_mark[i] = 0; ! 127: ! 128: /* for the slow speeds, we try to buffer 0.02 of the baud rate ! 129: (20% of the character rate). For the faster lines, ! 130: we try to buffer 1/2 the input queue size */ ! 131: ! 132: #undef _PR ! 133: #define _PR(x) (0.20 * x) ! 134: ! 135: pdma_water_mark[B300] = _PR(120); ! 136: pdma_water_mark[B600] = _PR(120); ! 137: pdma_water_mark[B1200] = _PR(120); ! 138: pdma_water_mark[B1800] = _PR(180); ! 139: pdma_water_mark[B2400] = _PR(240); ! 140: pdma_water_mark[B4800] = _PR(480); ! 141: i = tty_inq_size/2; ! 142: pdma_water_mark[B9600] = i; ! 143: pdma_water_mark[EXTA] = i; /* >14400 baud */ ! 144: pdma_water_mark[EXTB] = i; /* >19200 baud */ ! 145: ! 146: return; ! 147: } ! 148: ! 149: /* ! 150: * Open TTY, waiting for CARR_ON. ! 151: * No locks may be held. ! 152: * May run on any CPU. ! 153: */ ! 154: io_return_t char_open( ! 155: int dev, ! 156: struct tty * tp, ! 157: dev_mode_t mode, ! 158: io_req_t ior) ! 159: { ! 160: spl_t s; ! 161: io_return_t rc = D_SUCCESS; ! 162: ! 163: s = spltty(); ! 164: simple_lock(&tp->t_lock); ! 165: ! 166: tp->t_dev = dev; ! 167: ! 168: if (tp->t_mctl) ! 169: (*tp->t_mctl)(tp, TM_DTR, DMSET); ! 170: ! 171: if (pdma_default) ! 172: tp->t_state |= TS_MIN; ! 173: ! 174: if ((tp->t_state & TS_CARR_ON) == 0) { ! 175: /* ! 176: * No carrier. ! 177: */ ! 178: if (mode & D_NODELAY) { ! 179: tp->t_state |= TS_ONDELAY; ! 180: } ! 181: else { ! 182: /* ! 183: * Don`t return from open until carrier detected. ! 184: */ ! 185: tp->t_state |= TS_WOPEN; ! 186: ! 187: ior->io_dev_ptr = (char *)tp; ! 188: ! 189: queue_delayed_reply(&tp->t_delayed_open, ior, char_open_done); ! 190: rc = D_IO_QUEUED; ! 191: goto out; ! 192: } ! 193: } ! 194: tp->t_state |= TS_ISOPEN; ! 195: if (tp->t_mctl) ! 196: (*tp->t_mctl)(tp, TM_RTS, DMBIS); ! 197: out: ! 198: simple_unlock(&tp->t_lock); ! 199: splx(s); ! 200: return rc; ! 201: } ! 202: ! 203: /* ! 204: * Retry wait for CARR_ON for open. ! 205: * No locks may be held. ! 206: * May run on any CPU. ! 207: */ ! 208: boolean_t char_open_done( ! 209: io_req_t ior) ! 210: { ! 211: register struct tty *tp = (struct tty *)ior->io_dev_ptr; ! 212: spl_t s = spltty(); ! 213: ! 214: simple_lock(&tp->t_lock); ! 215: if ((tp->t_state & TS_ISOPEN) == 0) { ! 216: queue_delayed_reply(&tp->t_delayed_open, ior, char_open_done); ! 217: simple_unlock(&tp->t_lock); ! 218: splx(s); ! 219: return FALSE; ! 220: } ! 221: ! 222: tp->t_state |= TS_ISOPEN; ! 223: tp->t_state &= ~TS_WOPEN; ! 224: ! 225: if (tp->t_mctl) ! 226: (*tp->t_mctl)(tp, TM_RTS, DMBIS); ! 227: ! 228: simple_unlock(&tp->t_lock); ! 229: splx(s); ! 230: ! 231: ior->io_error = D_SUCCESS; ! 232: (void) ds_open_done(ior); ! 233: return TRUE; ! 234: } ! 235: ! 236: boolean_t tty_close_open_reply( ! 237: io_req_t ior) ! 238: { ! 239: ior->io_error = D_DEVICE_DOWN; ! 240: (void) ds_open_done(ior); ! 241: return TRUE; ! 242: } ! 243: ! 244: /* ! 245: * Write to TTY. ! 246: * No locks may be held. ! 247: * Calls device start routine; must already be on master if ! 248: * device needs to run on master. ! 249: */ ! 250: io_return_t char_write( ! 251: register struct tty * tp, ! 252: register io_req_t ior) ! 253: { ! 254: spl_t s; ! 255: register int count; ! 256: register char *data; ! 257: vm_offset_t addr; ! 258: io_return_t rc = D_SUCCESS; ! 259: ! 260: data = ior->io_data; ! 261: count = ior->io_count; ! 262: if (count == 0) ! 263: return rc; ! 264: ! 265: if (!(ior->io_op & IO_INBAND)) { ! 266: /* ! 267: * Copy out-of-line data into kernel address space. ! 268: * Since data is copied as page list, it will be ! 269: * accessible. ! 270: */ ! 271: vm_map_copy_t copy = (vm_map_copy_t) data; ! 272: kern_return_t kr; ! 273: ! 274: kr = vm_map_copyout(device_io_map, &addr, copy); ! 275: if (kr != KERN_SUCCESS) ! 276: return kr; ! 277: data = (char *) addr; ! 278: } ! 279: ! 280: /* ! 281: * Check for tty operating. ! 282: */ ! 283: s = spltty(); ! 284: simple_lock(&tp->t_lock); ! 285: ! 286: if ((tp->t_state & TS_CARR_ON) == 0) { ! 287: ! 288: if ((tp->t_state & TS_ONDELAY) == 0) { ! 289: /* ! 290: * No delayed writes - tell caller that device is down ! 291: */ ! 292: rc = D_IO_ERROR; ! 293: goto out; ! 294: } ! 295: ! 296: if (ior->io_mode & D_NOWAIT) { ! 297: rc = D_WOULD_BLOCK; ! 298: goto out; ! 299: } ! 300: } ! 301: ! 302: /* ! 303: * Copy data into the output buffer. ! 304: * Report the amount not copied. ! 305: */ ! 306: ! 307: ior->io_residual = b_to_q(data, count, &tp->t_outq); ! 308: ! 309: /* ! 310: * Start hardware output. ! 311: */ ! 312: ! 313: tp->t_state &= ~TS_TTSTOP; ! 314: tty_output(tp); ! 315: ! 316: if (tp->t_outq.c_cc > TTHIWAT(tp) || ! 317: (tp->t_state & TS_CARR_ON) == 0) { ! 318: ! 319: /* ! 320: * Do not send reply until some characters have been sent. ! 321: */ ! 322: ior->io_dev_ptr = (char *)tp; ! 323: queue_delayed_reply(&tp->t_delayed_write, ior, char_write_done); ! 324: ! 325: rc = D_IO_QUEUED; ! 326: } ! 327: out: ! 328: simple_unlock(&tp->t_lock); ! 329: splx(s); ! 330: ! 331: if (!(ior->io_op & IO_INBAND)) ! 332: (void) vm_deallocate(device_io_map, addr, ior->io_count); ! 333: return rc; ! 334: } ! 335: ! 336: /* ! 337: * Retry wait for output queue emptied, for write. ! 338: * No locks may be held. ! 339: * May run on any CPU. ! 340: */ ! 341: boolean_t char_write_done( ! 342: register io_req_t ior) ! 343: { ! 344: register struct tty *tp = (struct tty *)ior->io_dev_ptr; ! 345: register spl_t s = spltty(); ! 346: ! 347: simple_lock(&tp->t_lock); ! 348: if (tp->t_outq.c_cc > TTHIWAT(tp) || ! 349: (tp->t_state & TS_CARR_ON) == 0) { ! 350: ! 351: queue_delayed_reply(&tp->t_delayed_write, ior, char_write_done); ! 352: simple_unlock(&tp->t_lock); ! 353: splx(s); ! 354: return FALSE; ! 355: } ! 356: simple_unlock(&tp->t_lock); ! 357: splx(s); ! 358: ! 359: if (IP_VALID(ior->io_reply_port)) { ! 360: (void) (*((ior->io_op & IO_INBAND) ? ! 361: ds_device_write_reply_inband : ! 362: ds_device_write_reply))(ior->io_reply_port, ! 363: ior->io_reply_port_type, ! 364: ior->io_error, ! 365: (int) (ior->io_total - ! 366: ior->io_residual)); ! 367: } ! 368: mach_device_deallocate(ior->io_device); ! 369: return TRUE; ! 370: } ! 371: ! 372: boolean_t tty_close_write_reply( ! 373: register io_req_t ior) ! 374: { ! 375: ior->io_residual = ior->io_count; ! 376: ior->io_error = D_DEVICE_DOWN; ! 377: (void) ds_write_done(ior); ! 378: return TRUE; ! 379: } ! 380: ! 381: /* ! 382: * Read from TTY. ! 383: * No locks may be held. ! 384: * May run on any CPU - does not talk to device driver. ! 385: */ ! 386: io_return_t char_read( ! 387: register struct tty *tp, ! 388: register io_req_t ior) ! 389: { ! 390: spl_t s; ! 391: kern_return_t rc; ! 392: ! 393: /* ! 394: * Allocate memory for read buffer. ! 395: */ ! 396: rc = device_read_alloc(ior, (vm_size_t)ior->io_count); ! 397: if (rc != KERN_SUCCESS) ! 398: return rc; ! 399: ! 400: s = spltty(); ! 401: simple_lock(&tp->t_lock); ! 402: if ((tp->t_state & TS_CARR_ON) == 0) { ! 403: ! 404: if ((tp->t_state & TS_ONDELAY) == 0) { ! 405: /* ! 406: * No delayed writes - tell caller that device is down ! 407: */ ! 408: rc = D_IO_ERROR; ! 409: goto out; ! 410: } ! 411: ! 412: if (ior->io_mode & D_NOWAIT) { ! 413: rc = D_WOULD_BLOCK; ! 414: goto out; ! 415: } ! 416: ! 417: } ! 418: ! 419: if (tp->t_inq.c_cc <= 0 || ! 420: (tp->t_state & TS_CARR_ON) == 0) { ! 421: ! 422: ior->io_dev_ptr = (char *)tp; ! 423: queue_delayed_reply(&tp->t_delayed_read, ior, char_read_done); ! 424: rc = D_IO_QUEUED; ! 425: goto out; ! 426: } ! 427: ! 428: ior->io_residual = ior->io_count - q_to_b(&tp->t_inq, ! 429: ior->io_data, ! 430: (int)ior->io_count); ! 431: if (tp->t_state & TS_RTS_DOWN) { ! 432: (*tp->t_mctl)(tp, TM_RTS, DMBIS); ! 433: tp->t_state &= ~TS_RTS_DOWN; ! 434: } ! 435: ! 436: out: ! 437: simple_unlock(&tp->t_lock); ! 438: splx(s); ! 439: return rc; ! 440: } ! 441: ! 442: /* ! 443: * Retry wait for characters, for read. ! 444: * No locks may be held. ! 445: * May run on any CPU - does not talk to device driver. ! 446: */ ! 447: boolean_t char_read_done( ! 448: register io_req_t ior) ! 449: { ! 450: register struct tty *tp = (struct tty *)ior->io_dev_ptr; ! 451: register spl_t s = spltty(); ! 452: ! 453: simple_lock(&tp->t_lock); ! 454: ! 455: if (tp->t_inq.c_cc <= 0 || ! 456: (tp->t_state & TS_CARR_ON) == 0) { ! 457: ! 458: queue_delayed_reply(&tp->t_delayed_read, ior, char_read_done); ! 459: simple_unlock(&tp->t_lock); ! 460: splx(s); ! 461: return FALSE; ! 462: } ! 463: ! 464: ior->io_residual = ior->io_count - q_to_b(&tp->t_inq, ! 465: ior->io_data, ! 466: (int)ior->io_count); ! 467: if (tp->t_state & TS_RTS_DOWN) { ! 468: (*tp->t_mctl)(tp, TM_RTS, DMBIS); ! 469: tp->t_state &= ~TS_RTS_DOWN; ! 470: } ! 471: ! 472: simple_unlock(&tp->t_lock); ! 473: splx(s); ! 474: ! 475: (void) ds_read_done(ior); ! 476: return TRUE; ! 477: } ! 478: ! 479: boolean_t tty_close_read_reply( ! 480: register io_req_t ior) ! 481: { ! 482: ior->io_residual = ior->io_count; ! 483: ior->io_error = D_DEVICE_DOWN; ! 484: (void) ds_read_done(ior); ! 485: return TRUE; ! 486: } ! 487: ! 488: /* ! 489: * Close the tty. ! 490: * Tty must be locked (at spltty). ! 491: * Iff modem control should run on master. ! 492: */ ! 493: void ttyclose( ! 494: register struct tty *tp) ! 495: { ! 496: register io_req_t ior; ! 497: ! 498: /* ! 499: * Flush the read and write queues. Signal ! 500: * the open queue so that those waiting for open ! 501: * to complete will see that the tty is closed. ! 502: */ ! 503: while ((ior = (io_req_t)dequeue_head(&tp->t_delayed_read)) != 0) { ! 504: ior->io_done = tty_close_read_reply; ! 505: iodone(ior); ! 506: } ! 507: while ((ior = (io_req_t)dequeue_head(&tp->t_delayed_write)) != 0) { ! 508: ior->io_done = tty_close_write_reply; ! 509: iodone(ior); ! 510: } ! 511: while ((ior = (io_req_t)dequeue_head(&tp->t_delayed_open)) != 0) { ! 512: ior->io_done = tty_close_open_reply; ! 513: iodone(ior); ! 514: } ! 515: ! 516: /* Close down modem */ ! 517: if (tp->t_mctl) { ! 518: (*tp->t_mctl)(tp, TM_BRK|TM_RTS, DMBIC); ! 519: if ((tp->t_state&(TS_HUPCLS|TS_WOPEN)) || (tp->t_state&TS_ISOPEN)==0) ! 520: (*tp->t_mctl)(tp, TM_HUP, DMSET); ! 521: } ! 522: ! 523: /* only save buffering bit, and carrier */ ! 524: tp->t_state = tp->t_state & (TS_MIN|TS_CARR_ON); ! 525: } ! 526: ! 527: /* ! 528: * Port-death routine to clean up reply messages. ! 529: */ ! 530: boolean_t ! 531: tty_queue_clean( ! 532: queue_t q, ! 533: ipc_port_t port, ! 534: boolean_t (*routine)(io_req_t) ) ! 535: { ! 536: register io_req_t ior; ! 537: ! 538: ior = (io_req_t)queue_first(q); ! 539: while (!queue_end(q, (queue_entry_t)ior)) { ! 540: if (ior->io_reply_port == port) { ! 541: remqueue(q, (queue_entry_t)ior); ! 542: ior->io_done = routine; ! 543: iodone(ior); ! 544: return TRUE; ! 545: } ! 546: ior = ior->io_next; ! 547: } ! 548: return FALSE; ! 549: } ! 550: ! 551: /* ! 552: * Handle port-death (dead reply port) for tty. ! 553: * No locks may be held. ! 554: * May run on any CPU. ! 555: */ ! 556: boolean_t ! 557: tty_portdeath( ! 558: struct tty * tp, ! 559: ipc_port_t port) ! 560: { ! 561: register spl_t spl = spltty(); ! 562: register boolean_t result; ! 563: ! 564: simple_lock(&tp->t_lock); ! 565: ! 566: /* ! 567: * The queues may never have been initialized ! 568: */ ! 569: if (tp->t_delayed_read.next == 0) { ! 570: result = FALSE; ! 571: } ! 572: else { ! 573: result = ! 574: tty_queue_clean(&tp->t_delayed_read, port, ! 575: tty_close_read_reply) ! 576: || tty_queue_clean(&tp->t_delayed_write, port, ! 577: tty_close_write_reply) ! 578: || tty_queue_clean(&tp->t_delayed_open, port, ! 579: tty_close_open_reply); ! 580: } ! 581: simple_unlock(&tp->t_lock); ! 582: splx(spl); ! 583: ! 584: return result; ! 585: } ! 586: ! 587: /* ! 588: * Get TTY status. ! 589: * No locks may be held. ! 590: * May run on any CPU. ! 591: */ ! 592: io_return_t tty_get_status( ! 593: register struct tty *tp, ! 594: dev_flavor_t flavor, ! 595: int * data, /* pointer to OUT array */ ! 596: natural_t *count) /* out */ ! 597: { ! 598: spl_t s; ! 599: ! 600: switch (flavor) { ! 601: case TTY_STATUS: ! 602: { ! 603: register struct tty_status *tsp = ! 604: (struct tty_status *) data; ! 605: ! 606: if (*count < TTY_STATUS_COUNT) ! 607: return (D_INVALID_OPERATION); ! 608: ! 609: s = spltty(); ! 610: simple_lock(&tp->t_lock); ! 611: ! 612: tsp->tt_ispeed = tp->t_ispeed; ! 613: tsp->tt_ospeed = tp->t_ospeed; ! 614: tsp->tt_breakc = tp->t_breakc; ! 615: tsp->tt_flags = tp->t_flags; ! 616: if (tp->t_state & TS_HUPCLS) ! 617: tsp->tt_flags |= TF_HUPCLS; ! 618: ! 619: simple_unlock(&tp->t_lock); ! 620: splx(s); ! 621: ! 622: *count = TTY_STATUS_COUNT; ! 623: break; ! 624: ! 625: } ! 626: default: ! 627: return D_INVALID_OPERATION; ! 628: } ! 629: return D_SUCCESS; ! 630: } ! 631: ! 632: /* ! 633: * Set TTY status. ! 634: * No locks may be held. ! 635: * Calls device start or stop routines; must already be on master if ! 636: * device needs to run on master. ! 637: */ ! 638: io_return_t tty_set_status( ! 639: register struct tty *tp, ! 640: dev_flavor_t flavor, ! 641: int * data, ! 642: natural_t count) ! 643: { ! 644: int s; ! 645: ! 646: switch (flavor) { ! 647: case TTY_FLUSH: ! 648: { ! 649: register int flags; ! 650: if (count < TTY_FLUSH_COUNT) ! 651: return D_INVALID_OPERATION; ! 652: ! 653: flags = *data; ! 654: if (flags == 0) ! 655: flags = D_READ | D_WRITE; ! 656: ! 657: s = spltty(); ! 658: simple_lock(&tp->t_lock); ! 659: tty_flush(tp, flags); ! 660: simple_unlock(&tp->t_lock); ! 661: splx(s); ! 662: ! 663: break; ! 664: } ! 665: case TTY_STOP: ! 666: /* stop output */ ! 667: s = spltty(); ! 668: simple_lock(&tp->t_lock); ! 669: if ((tp->t_state & TS_TTSTOP) == 0) { ! 670: tp->t_state |= TS_TTSTOP; ! 671: (*tp->t_stop)(tp, 0); ! 672: } ! 673: simple_unlock(&tp->t_lock); ! 674: splx(s); ! 675: break; ! 676: ! 677: case TTY_START: ! 678: /* start output */ ! 679: s = spltty(); ! 680: simple_lock(&tp->t_lock); ! 681: if (tp->t_state & TS_TTSTOP) { ! 682: tp->t_state &= ~TS_TTSTOP; ! 683: tty_output(tp); ! 684: } ! 685: simple_unlock(&tp->t_lock); ! 686: splx(s); ! 687: break; ! 688: ! 689: case TTY_STATUS: ! 690: /* set special characters and speed */ ! 691: { ! 692: register struct tty_status *tsp; ! 693: ! 694: if (count < TTY_STATUS_COUNT) ! 695: return D_INVALID_OPERATION; ! 696: ! 697: tsp = (struct tty_status *)data; ! 698: ! 699: if (tsp->tt_ispeed < 0 || ! 700: tsp->tt_ispeed >= NSPEEDS || ! 701: tsp->tt_ospeed < 0 || ! 702: tsp->tt_ospeed >= NSPEEDS) ! 703: { ! 704: return D_INVALID_OPERATION; ! 705: } ! 706: ! 707: s = spltty(); ! 708: simple_lock(&tp->t_lock); ! 709: ! 710: tp->t_ispeed = tsp->tt_ispeed; ! 711: tp->t_ospeed = tsp->tt_ospeed; ! 712: tp->t_breakc = tsp->tt_breakc; ! 713: tp->t_flags = tsp->tt_flags & ~TF_HUPCLS; ! 714: if (tsp->tt_flags & TF_HUPCLS) ! 715: tp->t_state |= TS_HUPCLS; ! 716: ! 717: simple_unlock(&tp->t_lock); ! 718: splx(s); ! 719: break; ! 720: } ! 721: default: ! 722: return D_INVALID_OPERATION; ! 723: } ! 724: return D_SUCCESS; ! 725: } ! 726: ! 727: ! 728: /* ! 729: * [internal] ! 730: * Queue IOR on reply queue, to wait for TTY operation. ! 731: * TTY must be locked (at spltty). ! 732: */ ! 733: void queue_delayed_reply( ! 734: queue_t qh, ! 735: io_req_t ior, ! 736: boolean_t (*io_done)(io_req_t) ) ! 737: { ! 738: ior->io_done = io_done; ! 739: enqueue_tail(qh, (queue_entry_t)ior); ! 740: } ! 741: ! 742: /* ! 743: * Retry delayed IO operations for TTY. ! 744: * TTY containing queue must be locked (at spltty). ! 745: */ ! 746: void tty_queue_completion( ! 747: register queue_t qh) ! 748: { ! 749: register io_req_t ior; ! 750: ! 751: while ((ior = (io_req_t)dequeue_head(qh)) != 0) { ! 752: iodone(ior); ! 753: } ! 754: } ! 755: ! 756: /* ! 757: * Set the default special characters. ! 758: * Since this routine is called whenever a tty has never been opened, ! 759: * we can initialize the queues here. ! 760: */ ! 761: void ttychars( ! 762: register struct tty *tp) ! 763: { ! 764: if ((tp->t_flags & TS_INIT) == 0) { ! 765: /* ! 766: * Initialize queues ! 767: */ ! 768: queue_init(&tp->t_delayed_open); ! 769: queue_init(&tp->t_delayed_read); ! 770: queue_init(&tp->t_delayed_write); ! 771: ! 772: /* ! 773: * Initialize character buffers ! 774: */ ! 775: cb_alloc(&tp->t_inq, tty_inq_size); ! 776: ! 777: /* if we might do modem flow control */ ! 778: if (tp->t_mctl && tp->t_inq.c_hog > 30) ! 779: tp->t_inq.c_hog -= 30; ! 780: ! 781: cb_alloc(&tp->t_outq, tty_outq_size); ! 782: ! 783: /* ! 784: * Mark initialized ! 785: */ ! 786: tp->t_state |= TS_INIT; ! 787: } ! 788: ! 789: tp->t_breakc = 0; ! 790: } ! 791: ! 792: /* ! 793: * Flush all TTY queues. ! 794: * Called at spltty, tty already locked. ! 795: * Calls device STOP routine; must already be on master if ! 796: * device needs to run on master. ! 797: */ ! 798: void tty_flush( ! 799: register struct tty *tp, ! 800: int rw) ! 801: { ! 802: if (rw & D_READ) { ! 803: cb_clear(&tp->t_inq); ! 804: tty_queue_completion(&tp->t_delayed_read); ! 805: } ! 806: if (rw & D_WRITE) { ! 807: tp->t_state &= ~TS_TTSTOP; ! 808: (*tp->t_stop)(tp, rw); ! 809: cb_clear(&tp->t_outq); ! 810: tty_queue_completion(&tp->t_delayed_write); ! 811: } ! 812: } ! 813: ! 814: /* ! 815: * Restart character output after a delay timeout. ! 816: * Calls device start routine - must be on master CPU. ! 817: * ! 818: * Timeout routines are called only on master CPU. ! 819: * What if device runs on a different CPU? ! 820: */ ! 821: void ttrstrt( ! 822: register struct tty *tp) ! 823: { ! 824: register spl_t s; ! 825: ! 826: s = spltty(); ! 827: simple_lock(&tp->t_lock); ! 828: ! 829: tp->t_state &= ~TS_TIMEOUT; ! 830: ttstart (tp); ! 831: ! 832: simple_unlock(&tp->t_lock); ! 833: splx(s); ! 834: } ! 835: ! 836: /* ! 837: * Start output on the typewriter. It is used from the top half ! 838: * after some characters have been put on the output queue, ! 839: * from the interrupt routine to transmit the next ! 840: * character, and after a timeout has finished. ! 841: * ! 842: * Called at spltty, tty already locked. ! 843: * Must be on master CPU if device runs on master. ! 844: */ ! 845: void ttstart(tp) ! 846: register struct tty *tp; ! 847: { ! 848: if ((tp->t_state & (TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0) { ! 849: /* ! 850: * Start up the hardware again ! 851: */ ! 852: (*tp->t_start)(tp); ! 853: ! 854: /* ! 855: * Wake up those waiting for write completion. ! 856: */ ! 857: if (tp->t_outq.c_cc <= TTLOWAT(tp)) ! 858: tty_queue_completion(&tp->t_delayed_write); ! 859: } ! 860: } ! 861: ! 862: /* ! 863: * Start character output, if the device is not busy or ! 864: * stopped or waiting for a timeout. ! 865: * ! 866: * Called at spltty, tty already locked. ! 867: * Must be on master CPU if device runs on master. ! 868: */ ! 869: void tty_output( ! 870: register struct tty *tp) ! 871: { ! 872: if ((tp->t_state & (TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) == 0) { ! 873: /* ! 874: * Not busy. Start output. ! 875: */ ! 876: (*tp->t_start)(tp); ! 877: ! 878: /* ! 879: * Wake up those waiting for write completion. ! 880: */ ! 881: if (tp->t_outq.c_cc <= TTLOWAT(tp)) ! 882: tty_queue_completion(&tp->t_delayed_write); ! 883: } ! 884: } ! 885: ! 886: /* ! 887: * Send any buffered recvd chars up to user ! 888: */ ! 889: void ttypush( ! 890: register struct tty *tp) ! 891: { ! 892: spl_t s = spltty(); ! 893: register int state; ! 894: ! 895: simple_lock(&tp->t_lock); ! 896: ! 897: /* ! 898: The pdma timeout has gone off. ! 899: If no character has been received since the timeout ! 900: was set, push any pending characters up. ! 901: If any characters were received in the last interval ! 902: then just reset the timeout and the character received bit. ! 903: */ ! 904: ! 905: state = tp->t_state; ! 906: ! 907: if (state & TS_MIN_TO) ! 908: { ! 909: if (state & TS_MIN_TO_RCV) ! 910: { /* a character was received */ ! 911: tp->t_state = state & ~TS_MIN_TO_RCV; ! 912: timeout(ttypush,tp,pdma_timeouts[tp->t_ispeed]); ! 913: } ! 914: else ! 915: { ! 916: tp->t_state = state & ~TS_MIN_TO; ! 917: if (tp->t_inq.c_cc) /* pending characters */ ! 918: tty_queue_completion(&tp->t_delayed_read); ! 919: } ! 920: } ! 921: else ! 922: { ! 923: tp->t_state = state & ~TS_MIN_TO_RCV;/* sanity */ ! 924: } ! 925: ! 926: simple_unlock(&tp->t_lock); ! 927: splx(s); ! 928: } ! 929: ! 930: /* ! 931: * Put input character on input queue. ! 932: * ! 933: * Called at spltty, tty already locked. ! 934: */ ! 935: void ttyinput( ! 936: unsigned int c, ! 937: struct tty *tp) ! 938: { ! 939: if (tp->t_inq.c_cc >= tp->t_inq.c_hog) { ! 940: /* ! 941: * Do not want to overflow input queue ! 942: */ ! 943: if (tp->t_mctl) { ! 944: (*tp->t_mctl)(tp, TM_RTS, DMBIC); ! 945: tp->t_state |= TS_RTS_DOWN; ! 946: } ! 947: tty_queue_completion(&tp->t_delayed_read); ! 948: return; ! 949: ! 950: } ! 951: ! 952: c &= 0xff; ! 953: ! 954: (void) putc(c, &tp->t_inq); ! 955: if ((tp->t_state & TS_MIN) == 0 || ! 956: tp->t_inq.c_cc > pdma_water_mark[tp->t_ispeed]) ! 957: { ! 958: /* ! 959: * No input buffering, or input minimum exceeded. ! 960: * Grab a request from input queue and queue it ! 961: * to io_done thread. ! 962: */ ! 963: if (tp->t_state & TS_MIN_TO) { ! 964: tp->t_state &= ~(TS_MIN_TO|TS_MIN_TO_RCV); ! 965: untimeout(ttypush, tp); ! 966: } ! 967: tty_queue_completion(&tp->t_delayed_read); ! 968: } ! 969: else { ! 970: /* ! 971: * Not enough characters. ! 972: * If no timeout is set, initiate the timeout ! 973: * Otherwise set the character received during timeout interval ! 974: * flag. ! 975: * One alternative approach would be just to reset the timeout ! 976: * into the future, but this involves making a timeout/untimeout ! 977: * call on every character. ! 978: */ ! 979: register int ptime = pdma_timeouts[tp->t_ispeed]; ! 980: if (ptime > 0) ! 981: { ! 982: if ((tp->t_state & TS_MIN_TO) == 0) ! 983: { ! 984: tp->t_state |= TS_MIN_TO; ! 985: timeout(ttypush, tp, ptime); ! 986: } ! 987: else ! 988: { ! 989: tp->t_state |= TS_MIN_TO_RCV; ! 990: } ! 991: } ! 992: } ! 993: } ! 994: ! 995: /* ! 996: * Put many characters on input queue. ! 997: * ! 998: * Called at spltty, tty already locked. ! 999: */ ! 1000: void ttyinput_many( ! 1001: struct tty *tp, ! 1002: unsigned char *chars, ! 1003: int count) ! 1004: { ! 1005: /* ! 1006: * Do not want to overflow input queue ! 1007: */ ! 1008: if (tp->t_inq.c_cc < tp->t_inq.c_hog) ! 1009: count -= b_to_q( chars, count, &tp->t_inq); ! 1010: ! 1011: tty_queue_completion(&tp->t_delayed_read); ! 1012: } ! 1013: ! 1014: ! 1015: /* ! 1016: * Handle modem control transition on a tty. ! 1017: * Flag indicates new state of carrier. ! 1018: * Returns FALSE if the line should be turned off. ! 1019: * ! 1020: * Called at spltty, tty already locked. ! 1021: */ ! 1022: boolean_t ttymodem( ! 1023: struct tty * tp, ! 1024: boolean_t carrier_up) ! 1025: { ! 1026: if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_flags & MDMBUF)) { ! 1027: /* ! 1028: * Flow control by carrier. Carrier down stops ! 1029: * output; carrier up restarts output. ! 1030: */ ! 1031: if (carrier_up) { ! 1032: tp->t_state &= ~TS_TTSTOP; ! 1033: tty_output(tp); ! 1034: } ! 1035: else if ((tp->t_state&TS_TTSTOP) == 0) { ! 1036: tp->t_state |= TS_TTSTOP; ! 1037: (*tp->t_stop)(tp, 0); ! 1038: } ! 1039: } ! 1040: else if (carrier_up) { ! 1041: /* ! 1042: * Carrier now on. ! 1043: */ ! 1044: tp->t_state |= TS_CARR_ON; ! 1045: tt_open_wakeup(tp); ! 1046: } ! 1047: else { ! 1048: /* ! 1049: * Lost carrier. ! 1050: */ ! 1051: tp->t_state &= ~TS_CARR_ON; ! 1052: if (tp->t_state & TS_ISOPEN && ! 1053: (tp->t_flags & NOHANG) == 0) ! 1054: { ! 1055: /* ! 1056: * Hang up TTY if carrier drops. ! 1057: * Need to alert users, somehow... ! 1058: */ ! 1059: tty_flush(tp, D_READ|D_WRITE); ! 1060: return FALSE; ! 1061: } ! 1062: } ! 1063: return TRUE; ! 1064: } ! 1065: ! 1066: /* ! 1067: * Similarly, handle transitions on the ClearToSend ! 1068: * signal. Nowadays, it is used by many modems as ! 1069: * a flow-control device: they turn it down to stop ! 1070: * us from sending more chars. We do the same with ! 1071: * the RequestToSend signal. [Yes, that is exactly ! 1072: * why those signals are defined in the standard.] ! 1073: * ! 1074: * Tty must be locked and on master. ! 1075: */ ! 1076: tty_cts( ! 1077: struct tty * tp, ! 1078: boolean_t cts_up) ! 1079: { ! 1080: if (tp->t_state & TS_ISOPEN){ ! 1081: if (cts_up) { ! 1082: tp->t_state &= ~(TS_TTSTOP|TS_BUSY); ! 1083: tty_output(tp); ! 1084: } else { ! 1085: tp->t_state |= (TS_TTSTOP|TS_BUSY); ! 1086: (*tp->t_stop)(tp, D_WRITE); ! 1087: } ! 1088: } ! 1089: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.