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