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