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