|
|
1.1 ! root 1: /* (-lgl ! 2: * COHERENT Driver Kit Version 1.1.0 ! 3: * Copyright (c) 1982, 1990 by Mark Williams Company. ! 4: * All rights reserved. May not be copied without permission. ! 5: -lgl) */ ! 6: /* ! 7: * Polled Serial Port Device Driver. ! 8: * - supports version 7 compatible ioctl ! 9: */ ! 10: ! 11: #include <sys/coherent.h> ! 12: #include <sys/ins8250.h> ! 13: #include <sys/stat.h> ! 14: #include <sys/uproc.h> ! 15: #include <sys/proc.h> ! 16: #include <sys/tty.h> /* indirectly includes sgtty.h */ ! 17: #include <sys/con.h> ! 18: #include <sys/devices.h> ! 19: #include <errno.h> ! 20: #include <sys/sched.h> /* CVTTOUT, IVTTOUT, SVTTOUT */ ! 21: #include <sys/poll_clk.h> ! 22: ! 23: /* ! 24: * Definitions. ! 25: * ! 26: * HSBAUD is the highest baud rate supported by this driver ! 27: * HS_HZ is the polling rate, i.e. the number of times per second ! 28: * at which all open ports are checked for input, output, and ! 29: * line status changes ! 30: * MAX_HSNUM is the maximum number of devices that can be polled ! 31: * using this driver and can be revised up or down ! 32: * PORT is a convenience macro for the base address of a port ! 33: * port_config is the structure of the initial configuration for each ! 34: * polled port; note that "speed" is NOT the actual baud rate, but ! 35: * the value of the symbol for that baud rate as defined in ! 36: * /usr/include/sgtty.h ! 37: */ ! 38: #define HSBAUD 9600 ! 39: #define HS_HZ (HSBAUD/6) ! 40: #define MAX_HSNUM 8 ! 41: #define PORT ((int)(tp->t_ddp)) ! 42: struct port_config { ! 43: int addr; /* base address of the 8250-family UART */ ! 44: int speed; /* B0..B19200 */ ! 45: }; ! 46: ! 47: /* ! 48: * Export Variables - these can be patched without recompiling and linking ! 49: * ! 50: * HSNUM is the actual number of polled serial ports, and should be ! 51: * less than or equal to MAX_HSNUM ! 52: * HS_PORTS is an array of address/speed pairs, one for each port ! 53: */ ! 54: int HSNUM = 4; ! 55: struct port_config HS_PORTS[MAX_HSNUM] = { ! 56: { 0x3F8, B9600 }, ! 57: { 0x2F8, B9600 }, ! 58: { 0x3E8, B9600 }, ! 59: { 0x2E8, B9600 } ! 60: }; ! 61: ! 62: /* ! 63: * Export Functions. ! 64: */ ! 65: int hsload(); ! 66: int hsopen(); ! 67: int hsclose(); ! 68: int hsread(); ! 69: int hswrite(); ! 70: int hsioctl(); ! 71: int hsunload(); ! 72: int hspoll(); ! 73: ! 74: int hscycle(); ! 75: int hsintr(); ! 76: int hsparam(); ! 77: int hsstart(); ! 78: int hsclk(); ! 79: int set_poll_rate(); ! 80: ! 81: /* ! 82: * Import Functions ! 83: */ ! 84: int nulldev(); ! 85: int nonedev(); ! 86: ! 87: /* ! 88: * Configuration table. ! 89: */ ! 90: CON hscon ={ ! 91: DFCHR|DFPOL, /* Flags */ ! 92: HS_MAJOR, /* Major index */ ! 93: hsopen, /* Open */ ! 94: hsclose, /* Close */ ! 95: nulldev, /* Block */ ! 96: hsread, /* Read */ ! 97: hswrite, /* Write */ ! 98: hsioctl, /* Ioctl */ ! 99: nulldev, /* Powerfail */ ! 100: nulldev, /* Timeout */ ! 101: hsload, /* Load */ ! 102: hsunload, /* Unload */ ! 103: hspoll /* Poll */ ! 104: }; ! 105: ! 106: /* ! 107: * Local variables. ! 108: */ ! 109: static TTY *hstty; ! 110: static TTY *hslimtty; ! 111: static TIM hstim; ! 112: static int poll_divisor; /* used in hsclk() and set_poll_rate() */ ! 113: static int iocbaud[MAX_HSNUM]; ! 114: static char ioclcr[MAX_HSNUM]; ! 115: ! 116: /* ! 117: * Time constant table. ! 118: * Indexed by ioctl baud rate. ! 119: */ ! 120: static ! 121: int timeconst[] = { ! 122: 0, /* 0 */ ! 123: 2304, /* 50 */ ! 124: 1536, /* 75 */ ! 125: 1047, /* 110 */ ! 126: 857, /* 134.5 */ ! 127: 768, /* 150 */ ! 128: 576, /* 200 */ ! 129: 384, /* 300 */ ! 130: 192, /* 600 */ ! 131: 96, /* 1200 */ ! 132: 64, /* 1800 */ ! 133: 58, /* 2000 */ ! 134: 48, /* 2400 */ ! 135: 32, /* 3600 */ ! 136: 24, /* 4800 */ ! 137: 16, /* 7200 */ ! 138: 12, /* 9600 */ ! 139: 6, /* 19200 */ ! 140: 6, /* EXTA */ ! 141: 6 /* EXTB */ ! 142: }; ! 143: ! 144: /* ! 145: * poll_hz[] is tied to timeconst[] - it gives the minimum polling ! 146: * rate for the corresponding port speed; it must be a multiple ! 147: * of 100 (system clock Hz) and >= baud/6 ! 148: */ ! 149: int poll_hz[] ={ ! 150: 0, /* 0 */ ! 151: 1*HZ, /* 50 */ ! 152: 1*HZ, /* 75 */ ! 153: 1*HZ, /* 110 */ ! 154: 1*HZ, /* 134.5 */ ! 155: 1*HZ, /* 150 */ ! 156: 1*HZ, /* 200 */ ! 157: 1*HZ, /* 300 */ ! 158: 1*HZ, /* 600 */ ! 159: 2*HZ, /* 1200 */ ! 160: 3*HZ, /* 1800 */ ! 161: 4*HZ, /* 2000 */ ! 162: 4*HZ, /* 2400 */ ! 163: 6*HZ, /* 3600 */ ! 164: 8*HZ, /* 4800 */ ! 165: 12*HZ, /* 7200 */ ! 166: 16*HZ, /* 9600 */ ! 167: 0, /* 19200 */ ! 168: 0, /* EXTA */ ! 169: 0 /* EXTB */ ! 170: }; ! 171: ! 172: /* ! 173: * Load Routine. ! 174: */ ! 175: static hsload() ! 176: { ! 177: register TTY * tp; ! 178: register int port; ! 179: int i, b; ! 180: ! 181: if ((hstty = (TTY *)kalloc(HSNUM*sizeof(TTY))) == 0) { ! 182: printf("hsload: can't allocate tty's\n"); ! 183: return; ! 184: } ! 185: kclear(hstty, HSNUM*sizeof(TTY)); ! 186: ! 187: for (i = 0; i < HSNUM; i++) { ! 188: port = HS_PORTS[i].addr; ! 189: tp = hstty + i; ! 190: ! 191: outb(port+MCR, 0); ! 192: outb(port+IER, 0); ! 193: ! 194: if (inb(port+IER)) ! 195: break; ! 196: ! 197: tp->t_cs_sel = cs_sel(); ! 198: tp->t_start = hsstart; ! 199: tp->t_param = hsparam; ! 200: tp->t_sgttyb.sg_ospeed = tp->t_sgttyb.sg_ispeed = ! 201: tp->t_dispeed = tp->t_dospeed = HS_PORTS[i].speed; ! 202: tp->t_ddp = port; ! 203: ! 204: b = timeconst[ tp->t_sgttyb.sg_ospeed ]; ! 205: outb(port+LCR, LC_DLAB); ! 206: outb(port+DLL, b); ! 207: outb(port+DLH, b >> 8); ! 208: outb(port+LCR, LC_CS8); ! 209: ! 210: hslimtty = tp; ! 211: } ! 212: } ! 213: ! 214: static hsunload() ! 215: { ! 216: if (hstty != (TTY *)0) ! 217: kfree(hstty); ! 218: } ! 219: ! 220: /* ! 221: * Open Routine. ! 222: */ ! 223: hsopen(dev, mode) ! 224: dev_t dev; ! 225: { ! 226: register TTY * tp = &hstty[ dev & 15 ]; ! 227: register int b; ! 228: int s; ! 229: ! 230: /* ! 231: * Verify hardware exists. ! 232: */ ! 233: if ((PORT == 0) || (inb(PORT+IER) & ~IE_TxI)) { ! 234: u.u_error = ENXIO; ! 235: return; ! 236: } ! 237: ! 238: /* ! 239: * Can't open if another driver is using polling ! 240: */ ! 241: if (poll_owner & ~ POLL_HS) { ! 242: u.u_error = EDBUSY; ! 243: return; ! 244: } ! 245: ! 246: /* ! 247: * Initialize if not already open. ! 248: */ ! 249: if (++tp->t_open == 1) { ! 250: ttopen(tp); ! 251: ! 252: if (dev & 0x80) { ! 253: s = sphi(); ! 254: b = inb(PORT+MSR); ! 255: tp->t_flags |= T_MODC + T_STOP; ! 256: if (b & MS_CTS) ! 257: tp->t_flags &= ~T_STOP; ! 258: if (b & MS_DSR) ! 259: tp->t_flags |= T_CARR; ! 260: spl(s); ! 261: } else { ! 262: tp->t_flags &= ~T_MODC; ! 263: tp->t_flags |= T_CARR; ! 264: } ! 265: hscycle(tp); ! 266: } ! 267: ttsetgrp(tp, dev); ! 268: set_poll_rate(); ! 269: } ! 270: ! 271: /* ! 272: * Close Routine. ! 273: */ ! 274: hsclose(dev) ! 275: dev_t dev; ! 276: { ! 277: register TTY * tp = &hstty[ dev & 15 ]; ! 278: ! 279: /* ! 280: * Reset if last close. ! 281: */ ! 282: if (tp->t_open == 1) { ! 283: int state; ! 284: ! 285: ttclose(tp); ! 286: /* ! 287: * ttclose() only emptied the output queue tp->t_oq; ! 288: * now wait 0.1 sec for the silo tp->rawout to empty ! 289: * and allow a delay for the UART on-chip xmit buffer to empty ! 290: * ! 291: * state 2: waiting for silo to empty ! 292: * state 1: stalling so UART can empty xmit buffer ! 293: * state 0: done! ! 294: */ ! 295: state = 2; ! 296: while (state) { ! 297: timeout(&hstim, 10, wakeup, (int)&hstim); ! 298: sleep((char *)&hstim, CVTTOUT, IVTTOUT, SVTTOUT); ! 299: if (tp->t_rawout.si_ix == tp->t_rawout.si_ox && state) ! 300: state--; ! 301: } ! 302: } ! 303: ! 304: --tp->t_open; ! 305: set_poll_rate(); ! 306: } ! 307: ! 308: /* ! 309: * Read Routine. ! 310: */ ! 311: hsread(dev, iop) ! 312: dev_t dev; ! 313: register IO * iop; ! 314: { ! 315: ttread(&hstty[ dev & 15 ], iop); ! 316: } ! 317: ! 318: /* ! 319: * Write Routine. ! 320: */ ! 321: hswrite(dev, iop) ! 322: dev_t dev; ! 323: register IO * iop; ! 324: { ! 325: ttwrite(&hstty[ dev & 15 ], iop); ! 326: } ! 327: ! 328: /* ! 329: * Ioctl Routine. ! 330: */ ! 331: hsioctl(dev, com, vec) ! 332: dev_t dev; ! 333: int com; ! 334: struct sgttyb * vec; ! 335: { ! 336: ttioctl(&hstty[ dev & 15 ], com, vec); ! 337: } ! 338: ! 339: /* ! 340: * Polling Routine. ! 341: */ ! 342: hspoll(dev, ev, msec) ! 343: dev_t dev; ! 344: int ev; ! 345: int msec; ! 346: { ! 347: return ttpoll(&hstty[ dev & 15 ], ev, msec); ! 348: } ! 349: ! 350: /* ! 351: * Cyclic routine - invoked every clock tick to perform raw input/output. ! 352: * ! 353: * Notes: Invoked 10 times per second. ! 354: */ ! 355: hscycle(tp) ! 356: register TTY * tp; ! 357: { ! 358: register int resid; ! 359: register int c; ! 360: ! 361: /* ! 362: * Process rawin buf. ! 363: */ ! 364: while (tp->t_rawin.si_ix != tp->t_rawin.si_ox) { ! 365: ! 366: ttin(tp, tp->t_rawin.si_buf[ tp->t_rawin.si_ox ]); ! 367: ! 368: if (tp->t_rawin.si_ox >= sizeof(tp->t_rawin.si_buf) - 1) ! 369: tp->t_rawin.si_ox = 0; ! 370: else ! 371: tp->t_rawin.si_ox++; ! 372: } ! 373: ! 374: /* ! 375: * Calculate free output slot count. ! 376: */ ! 377: resid = sizeof(tp->t_rawout.si_buf) - 1; ! 378: resid += tp->t_rawout.si_ox - tp->t_rawout.si_ix; ! 379: resid %= sizeof(tp->t_rawout.si_buf); ! 380: ! 381: /* ! 382: * Fill raw output buffer. ! 383: */ ! 384: while ((--resid >= 0) && ((c = ttout(tp)) >= 0)) { ! 385: ! 386: tp->t_rawout.si_buf[ tp->t_rawout.si_ix ] = c; ! 387: ! 388: if (tp->t_rawout.si_ix >= sizeof(tp->t_rawout.si_buf) - 1) ! 389: tp->t_rawout.si_ix = 0; ! 390: else ! 391: tp->t_rawout.si_ix++; ! 392: } ! 393: ! 394: /* ! 395: * (Re)start output, waking processes waiting to output, etc. ! 396: */ ! 397: ttstart(tp); ! 398: ! 399: /* ! 400: * Schedule next cycle. ! 401: */ ! 402: if (tp->t_open != 0) ! 403: timeout(&tp->t_rawtim, HZ/10, hscycle, tp); ! 404: } ! 405: ! 406: /* ! 407: * Clock Interrupt driven Polling routine. ! 408: */ ! 409: hsintr() ! 410: { ! 411: register TTY * tp = &hstty[0]; ! 412: register int b; ! 413: ! 414: do { ! 415: if (tp->t_open == 0) ! 416: continue; ! 417: ! 418: /* ! 419: * Check modem status if modem control is enabled. ! 420: */ ! 421: if (tp->t_flags & T_MODC) { ! 422: ! 423: b = inb(PORT+MSR); ! 424: ! 425: if (b & (MS_DCTS|MS_DDSR)) { ! 426: ! 427: if (b & MS_DCTS) { ! 428: if (b & MS_CTS) ! 429: tp->t_flags &= ~T_STOP; ! 430: else ! 431: tp->t_flags |= T_STOP; ! 432: } ! 433: if (b & MS_DDSR) { ! 434: if (b & MS_DSR) ! 435: tp->t_flags |= T_CARR; ! 436: else { ! 437: tp->t_flags &= ~T_CARR; ! 438: tthup(tp); ! 439: } ! 440: } ! 441: } ! 442: } ! 443: ! 444: b = inb(PORT+LSR); ! 445: ! 446: if ((b & LS_BREAK) && (tp->t_flags & T_CARR)) ! 447: ttsignal(tp, SIGINT); ! 448: ! 449: /* ! 450: * Receive ready. ! 451: */ ! 452: if (b & LS_RxRDY) { ! 453: ! 454: tp->t_rawin.si_buf[tp->t_rawin.si_ix] = inb(PORT+DREG); ! 455: ! 456: if (tp->t_flags & T_CARR) { ! 457: ! 458: if (++(tp->t_rawin.si_ix) >= ! 459: sizeof(tp->t_rawin.si_buf)) ! 460: tp->t_rawin.si_ix = 0; ! 461: } ! 462: } ! 463: ! 464: /* ! 465: * Transmit ready and raw output data exists. ! 466: */ ! 467: if ((b & LS_TxRDY) && ((tp->t_flags & T_STOP) == 0) ! 468: && (tp->t_rawout.si_ix != tp->t_rawout.si_ox)) { ! 469: ! 470: outb( PORT+DREG, ! 471: tp->t_rawout.si_buf[ tp->t_rawout.si_ox ]); ! 472: ! 473: if (++(tp->t_rawout.si_ox) >= ! 474: sizeof(tp->t_rawout.si_buf)) ! 475: tp->t_rawout.si_ox = 0; ! 476: } ! 477: ! 478: } while (++tp <= hslimtty); ! 479: } ! 480: ! 481: /* ! 482: * Set hardware parameters. ! 483: */ ! 484: hsparam(tp) ! 485: register TTY * tp; ! 486: { ! 487: register int b; ! 488: int s; ! 489: int hnum; ! 490: int newbaud; ! 491: char newlcr; ! 492: int write_baud = 1, write_lcr = 1; ! 493: ! 494: newbaud = timeconst[tp->t_sgttyb.sg_ospeed]; ! 495: ! 496: switch (tp->t_sgttyb.sg_flags & (EVENP|ODDP|RAW)) { ! 497: case ODDP: ! 498: newlcr = LC_CS7|LC_PARENB; ! 499: break; ! 500: case EVENP: ! 501: newlcr = LC_CS7|LC_PARENB|LC_PAREVEN; ! 502: break; ! 503: default: ! 504: newlcr = LC_CS8; ! 505: break; ! 506: } ! 507: ! 508: hnum = tp - hstty; ! 509: if (hnum >= 0 && hnum < HSNUM) { ! 510: if (newbaud == iocbaud[hnum]) { ! 511: write_baud = 0; ! 512: if (newlcr == ioclcr[hnum]) { ! 513: write_lcr = 0; ! 514: } ! 515: } ! 516: iocbaud[hnum] = newbaud; ! 517: ioclcr[hnum] = newlcr; ! 518: } ! 519: ! 520: s = sphi(); ! 521: /* ! 522: * Assert required modem control lines (DTR, RTS). ! 523: */ ! 524: if (tp->t_sgttyb.sg_ospeed == B0) { ! 525: outb(PORT+MCR, 0); ! 526: } else { ! 527: outb(PORT+MCR, MC_DTR | MC_RTS); ! 528: } ! 529: ! 530: /* ! 531: * Program baud rate. ! 532: */ ! 533: if (write_baud) { ! 534: outb(PORT+LCR, LC_DLAB); ! 535: outb(PORT+DLL, newbaud); ! 536: outb(PORT+DLH, newbaud >> 8); ! 537: } ! 538: ! 539: /* ! 540: * Program character size, parity. ! 541: */ ! 542: if (write_lcr) ! 543: outb(PORT+LCR, newlcr); ! 544: ! 545: /* ! 546: * Enable Transmit Buffer Empty Interrupts. ! 547: */ ! 548: outb(PORT+IER, IE_TxI); ! 549: ! 550: spl(s); ! 551: set_poll_rate(); ! 552: } ! 553: ! 554: /* ! 555: * Start Routine. ! 556: */ ! 557: hsstart(tp) ! 558: register TTY * tp; ! 559: { ! 560: register int s; ! 561: ! 562: /* ! 563: * Transmit buffer is empty, and raw output buffer is not. ! 564: */ ! 565: s = sphi(); ! 566: if ((inb(PORT+LSR) & LS_TxRDY) ! 567: && (tp->t_rawout.si_ix != tp->t_rawout.si_ox)) { ! 568: ! 569: /* ! 570: * Send next char from raw output buffer. ! 571: */ ! 572: outb(PORT+DREG, tp->t_rawout.si_buf[ tp->t_rawout.si_ox ]); ! 573: ! 574: if (++tp->t_rawout.si_ox >= sizeof(tp->t_rawout.si_buf)) ! 575: tp->t_rawout.si_ox = 0; ! 576: } ! 577: spl(s); ! 578: } ! 579: ! 580: /* ! 581: * hsclk will be called every time T0 interrupts - if it returns 0, ! 582: * the usual system timer interrupt stuff is done ! 583: */ ! 584: static int hsclk() ! 585: { ! 586: static int count; ! 587: ! 588: hsintr(); ! 589: count++; ! 590: if (count >= poll_divisor) ! 591: count = 0; ! 592: return count; ! 593: } ! 594: ! 595: /* ! 596: * set_poll_rate is called when a port is opened or closed or changes speed ! 597: * it sets the polling rate only as fast as needed, and shuts off polling ! 598: * whenever possible ! 599: */ ! 600: static set_poll_rate() ! 601: { ! 602: int port_num, max_rate, port_rate; ! 603: ! 604: /* ! 605: * If another driver has the polling clock, do nothing. ! 606: */ ! 607: if (poll_owner & ~ POLL_HS) ! 608: return; ! 609: ! 610: /* ! 611: * find highest valid polling rate in units of HZ/10 ! 612: */ ! 613: max_rate = 0; ! 614: for (port_num = 0; port_num < HSNUM; port_num++) { ! 615: if (hstty[port_num].t_open) { ! 616: port_rate = poll_hz[hstty[port_num].t_sgttyb.sg_ispeed]; ! 617: if (max_rate < port_rate) ! 618: max_rate = port_rate; ! 619: } ! 620: } ! 621: /* ! 622: * if max_rate is not current rate, adjust the system clock ! 623: */ ! 624: if (max_rate != poll_rate) { ! 625: poll_rate = max_rate; ! 626: poll_divisor = poll_rate/HZ; /* used in hsclk() */ ! 627: altclk_out(); /* stop previous polling */ ! 628: poll_owner &= ~POLL_HS; ! 629: if (max_rate) { /* resume polling at new rate if needed */ ! 630: altclk_in(poll_rate, hsclk); ! 631: poll_owner |= POLL_HS; ! 632: } ! 633: } ! 634: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.