|
|
1.1 ! root 1: /* ! 2: * Interrupt Driver Multi-Port Device Driver. ! 3: * - supports version 7 compatible ioctl ! 4: */ ! 5: ! 6: #include "coherent.h" ! 7: #include "ins8250.h" ! 8: #include <sys/stat.h> ! 9: #include <sys/uproc.h> ! 10: #include <sys/proc.h> ! 11: #include <sys/tty.h> /* indirectly includes sgtty.h */ ! 12: #include <sys/con.h> ! 13: #include <errno.h> ! 14: #include <sys/timeout.h> /* TIM */ ! 15: #include <sched.h> /* CVTTOUT, IVTTOUT, SVTTOUT */ ! 16: #include <poll_clk.h> ! 17: ! 18: /* ! 19: * Definitions. ! 20: * ! 21: * MAX_GCNUM is the maximum number of devices that can be polled ! 22: * using this driver and can be revised up or down ! 23: * PORT is a convenience macro for the base address of a port ! 24: * port_config is the structure of the initial configuration for each ! 25: * polled port; note that "speed" is NOT the actual baud rate, but ! 26: * the value of the symbol for that baud rate as defined in ! 27: * /usr/include/sgtty.h ! 28: * GCINT is the IRQ number for the interrupt belonging to the board. ! 29: * On the AT, IRQ2 is mapped to the same vector as IRQ9. ! 30: */ ! 31: #define MAX_GCNUM 8 ! 32: #define PORT ((int)(tp->t_ddp)) ! 33: struct port_config { ! 34: int addr; /* base address of the 8250-family UART */ ! 35: int speed; /* B0..B19200 */ ! 36: }; ! 37: #define GCINT 2 ! 38: ! 39: /* ! 40: * Export Variables - these can be patched without recompiling and linking ! 41: * ! 42: * GCNUM is the actual number of polled serial ports, and should be ! 43: * less than or equal to MAX_GCNUM ! 44: * GCIRPT is the I/O address of the multiport interrupt register; ! 45: * a value of 0 in bit 0..3 means a pending interrupt for port 0..3 ! 46: * GC_PORTS is an array of address/speed pairs, one for each port ! 47: */ ! 48: int GCNUM = 4; ! 49: int GCIRPT = 0x2BF; ! 50: /* ! 51: * Defaults are for PC COM4, Enhanced Mode, High Address. ! 52: */ ! 53: struct port_config GC_PORTS[MAX_GCNUM] = { ! 54: { 0x2A0, B9600 }, ! 55: { 0x2A8, B9600 }, ! 56: { 0x2B0, B9600 }, ! 57: { 0x2B8, B9600 } ! 58: }; ! 59: ! 60: /* ! 61: * Export Functions. ! 62: */ ! 63: int gcload(); ! 64: int gcopen(); ! 65: int gcclose(); ! 66: int gcread(); ! 67: int gcwrite(); ! 68: int gcioctl(); ! 69: int gcunload(); ! 70: int gcpoll(); ! 71: ! 72: int gccycle(); ! 73: int gcintr(); ! 74: int gcparam(); ! 75: int gcstart(); ! 76: ! 77: /* ! 78: * Import Functions ! 79: */ ! 80: int nulldev(); ! 81: int nonedev(); ! 82: ! 83: /* ! 84: * Configuration table. ! 85: */ ! 86: CON gccon ={ ! 87: DFCHR|DFPOL, /* Flags */ ! 88: GCINT, /* Major index */ ! 89: gcopen, /* Open */ ! 90: gcclose, /* Close */ ! 91: nulldev, /* Block */ ! 92: gcread, /* Read */ ! 93: gcwrite, /* Write */ ! 94: gcioctl, /* Ioctl */ ! 95: nulldev, /* Powerfail */ ! 96: nulldev, /* Timeout */ ! 97: gcload, /* Load */ ! 98: gcunload, /* Unload */ ! 99: gcpoll /* Poll */ ! 100: }; ! 101: ! 102: /* ! 103: * Local variables. ! 104: */ ! 105: static TTY *hstty; ! 106: static TTY *hslimtty; ! 107: static TIM hstim; ! 108: ! 109: /* ! 110: * Time constant table. ! 111: * Indexed by ioctl baud rate. ! 112: */ ! 113: static ! 114: int timeconst[] = { ! 115: 0, /* 0 */ ! 116: 2304, /* 50 */ ! 117: 1536, /* 75 */ ! 118: 1047, /* 110 */ ! 119: 857, /* 134.5 */ ! 120: 768, /* 150 */ ! 121: 576, /* 200 */ ! 122: 384, /* 300 */ ! 123: 192, /* 600 */ ! 124: 96, /* 1200 */ ! 125: 64, /* 1800 */ ! 126: 58, /* 2000 */ ! 127: 48, /* 2400 */ ! 128: 32, /* 3600 */ ! 129: 24, /* 4800 */ ! 130: 16, /* 7200 */ ! 131: 12, /* 9600 */ ! 132: 6, /* 19200 */ ! 133: 6, /* EXTA */ ! 134: 6 /* EXTB */ ! 135: }; ! 136: ! 137: /* ! 138: * Load Routine. ! 139: */ ! 140: static gcload() ! 141: { ! 142: register TTY * tp; ! 143: register int port; ! 144: int i, b, s; ! 145: ! 146: if ((hstty = (TTY *)kalloc(GCNUM*sizeof(TTY))) == 0) { ! 147: printf("gcload: can't allocate tty's\n"); ! 148: return; ! 149: } ! 150: kclear(hstty, GCNUM*sizeof(TTY)); ! 151: ! 152: s = sphi(); ! 153: for (i = 0; i < GCNUM; i++) { ! 154: port = GC_PORTS[i].addr; ! 155: tp = hstty + i; ! 156: ! 157: outb( port+MCR, 0 ); ! 158: outb( port+IER, 0 ); ! 159: ! 160: if ( inb( port+IER ) ) ! 161: break; ! 162: ! 163: tp->t_cs_sel = cs_sel(); ! 164: tp->t_start = gcstart; ! 165: tp->t_param = gcparam; ! 166: tp->t_sgttyb.sg_ospeed = tp->t_sgttyb.sg_ispeed = ! 167: tp->t_dispeed = tp->t_dospeed = GC_PORTS[i].speed; ! 168: tp->t_ddp = port; ! 169: ! 170: b = timeconst[ 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: hslimtty = tp; ! 177: } ! 178: setivec(GCINT, gcintr); ! 179: spl(s); ! 180: } ! 181: ! 182: static gcunload() ! 183: { ! 184: clrivec(GCINT); ! 185: kfree(hstty); ! 186: } ! 187: ! 188: /* ! 189: * Open Routine. ! 190: */ ! 191: gcopen( dev, mode ) ! 192: dev_t dev; ! 193: { ! 194: register TTY * tp = &hstty[ dev & 15 ]; ! 195: register int b; ! 196: int s; ! 197: ! 198: /* ! 199: * Verify hardware exists. ! 200: */ ! 201: if ( (PORT == 0) || (inb(PORT+IER) & ~IE_TxI) ) { ! 202: u.u_error = ENXIO; ! 203: return; ! 204: } ! 205: ! 206: /* ! 207: * Initialize if not already open. ! 208: */ ! 209: if ( ++tp->t_open == 1 ) { ! 210: ttopen( tp ); ! 211: ! 212: if ( dev & 0x80 ) { ! 213: s = sphi(); ! 214: b = inb(PORT+MSR); ! 215: tp->t_flags |= T_MODC + T_STOP; ! 216: if ( b & MS_CTS ) ! 217: tp->t_flags &= ~T_STOP; ! 218: if ( b & MS_DSR ) ! 219: tp->t_flags |= T_CARR; ! 220: spl( s ); ! 221: } else { ! 222: tp->t_flags &= ~T_MODC; ! 223: tp->t_flags |= T_CARR; ! 224: } ! 225: gccycle( tp ); ! 226: } ! 227: ttsetgrp( tp, dev ); ! 228: } ! 229: ! 230: /* ! 231: * Close Routine. ! 232: */ ! 233: gcclose( dev ) ! 234: dev_t dev; ! 235: { ! 236: register TTY * tp = &hstty[ dev & 15 ]; ! 237: ! 238: /* ! 239: * Reset if last close. ! 240: */ ! 241: if ( tp->t_open == 1 ) { ! 242: int state; ! 243: ! 244: ttclose( tp ); ! 245: /* ! 246: * ttclose() only emptied the output queue tp->t_oq; ! 247: * now wait 0.1 sec for the silo tp->rawout to empty ! 248: * and allow a delay for the UART on-chip xmit buffer to empty ! 249: * ! 250: * state 2: waiting for silo to empty ! 251: * state 1: stalling so UART can empty xmit buffer ! 252: * state 0: done! ! 253: */ ! 254: state = 2; ! 255: while (state) { ! 256: timeout(&hstim, 10, wakeup, (int)&hstim); ! 257: sleep((char *)&hstim, CVTTOUT, IVTTOUT, SVTTOUT); ! 258: if (tp->t_rawout.si_ix == tp->t_rawout.si_ox && state) ! 259: state--; ! 260: } ! 261: } ! 262: ! 263: --tp->t_open; ! 264: } ! 265: ! 266: /* ! 267: * Read Routine. ! 268: */ ! 269: gcread( dev, iop ) ! 270: dev_t dev; ! 271: register IO * iop; ! 272: { ! 273: ttread( &hstty[ dev & 15 ], iop, 0 ); ! 274: } ! 275: ! 276: /* ! 277: * Write Routine. ! 278: */ ! 279: gcwrite( dev, iop ) ! 280: dev_t dev; ! 281: register IO * iop; ! 282: { ! 283: ttwrite( &hstty[ dev & 15 ], iop, 0 ); ! 284: } ! 285: ! 286: /* ! 287: * Ioctl Routine. ! 288: */ ! 289: gcioctl( dev, com, vec ) ! 290: dev_t dev; ! 291: int com; ! 292: struct sgttyb * vec; ! 293: { ! 294: ttioctl( &hstty[ dev & 15 ], com, vec ); ! 295: } ! 296: ! 297: /* ! 298: * Polling Routine. ! 299: */ ! 300: gcpoll( dev, ev, msec ) ! 301: dev_t dev; ! 302: int ev; ! 303: int msec; ! 304: { ! 305: return ttpoll( &hstty[ dev & 15 ], ev, msec ); ! 306: } ! 307: ! 308: /* ! 309: * Cyclic routine - invoked every clock tick to perform raw input/output. ! 310: * ! 311: * Notes: Invoked 10 times per second. ! 312: */ ! 313: gccycle( tp ) ! 314: register TTY * tp; ! 315: { ! 316: register int resid; ! 317: register int c; ! 318: ! 319: /* ! 320: * Process rawin buf. ! 321: */ ! 322: while ( tp->t_rawin.si_ix != tp->t_rawin.si_ox ) { ! 323: ! 324: ttin( tp, tp->t_rawin.si_buf[ tp->t_rawin.si_ox ] ); ! 325: ! 326: if ( tp->t_rawin.si_ox >= sizeof(tp->t_rawin.si_buf) - 1 ) ! 327: tp->t_rawin.si_ox = 0; ! 328: else ! 329: tp->t_rawin.si_ox++; ! 330: } ! 331: ! 332: /* ! 333: * Calculate free output slot count. ! 334: */ ! 335: resid = sizeof(tp->t_rawout.si_buf) - 1; ! 336: resid += tp->t_rawout.si_ox - tp->t_rawout.si_ix; ! 337: resid %= sizeof(tp->t_rawout.si_buf); ! 338: ! 339: /* ! 340: * Fill raw output buffer. ! 341: */ ! 342: while ( (--resid >= 0) && ((c = ttout(tp)) >= 0) ) { ! 343: ! 344: tp->t_rawout.si_buf[ tp->t_rawout.si_ix ] = c; ! 345: ! 346: if ( tp->t_rawout.si_ix >= sizeof(tp->t_rawout.si_buf) - 1 ) ! 347: tp->t_rawout.si_ix = 0; ! 348: else ! 349: tp->t_rawout.si_ix++; ! 350: } ! 351: ! 352: /* ! 353: * (Re)start output, waking processes waiting to output, etc. ! 354: */ ! 355: ttstart( tp ); ! 356: ! 357: /* ! 358: * Schedule next cycle. ! 359: */ ! 360: if ( tp->t_open != 0 ) ! 361: timeout( &tp->t_rawtim, HZ/10, gccycle, tp ); ! 362: } ! 363: ! 364: /* ! 365: * Interrupt driven Polling routine. ! 366: */ ! 367: gcintr() ! 368: { ! 369: register TTY * tp = &hstty[0]; ! 370: register int b; ! 371: ! 372: do { ! 373: if ( tp->t_open == 0 ) ! 374: continue; ! 375: ! 376: /* ! 377: * Check modem status if modem control is enabled. ! 378: */ ! 379: if ( tp->t_flags & T_MODC ) { ! 380: ! 381: b = inb( PORT+MSR ); ! 382: ! 383: if ( b & (MS_DCTS|MS_DDSR) ) { ! 384: ! 385: if ( b & MS_DCTS ) { ! 386: if ( b & MS_CTS ) ! 387: tp->t_flags &= ~T_STOP; ! 388: else ! 389: tp->t_flags |= T_STOP; ! 390: } ! 391: if ( b & MS_DDSR ) { ! 392: if ( b & MS_DSR ) ! 393: tp->t_flags |= T_CARR; ! 394: else { ! 395: tp->t_flags &= ~T_CARR; ! 396: tthup( tp ); ! 397: } ! 398: } ! 399: } ! 400: } ! 401: ! 402: b = inb( PORT+LSR ); ! 403: ! 404: if ( (b & LS_BREAK) && (tp->t_flags & T_CARR) ) ! 405: ttsignal( tp, SIGINT ); ! 406: ! 407: /* ! 408: * Receive ready. ! 409: */ ! 410: if ( b & LS_RxRDY ) { ! 411: ! 412: tp->t_rawin.si_buf[tp->t_rawin.si_ix] = inb(PORT+DREG); ! 413: ! 414: if ( tp->t_flags & T_CARR ) { ! 415: ! 416: if ( ++(tp->t_rawin.si_ix) >= ! 417: sizeof(tp->t_rawin.si_buf) ) ! 418: tp->t_rawin.si_ix = 0; ! 419: } ! 420: } ! 421: ! 422: /* ! 423: * Transmit ready and raw output data exists. ! 424: */ ! 425: if ( (b & LS_TxRDY) && ((tp->t_flags & T_STOP) == 0) ! 426: && (tp->t_rawout.si_ix != tp->t_rawout.si_ox) ) { ! 427: ! 428: outb( PORT+DREG, ! 429: tp->t_rawout.si_buf[ tp->t_rawout.si_ox ] ); ! 430: ! 431: if ( ++(tp->t_rawout.si_ox) >= ! 432: sizeof(tp->t_rawout.si_buf) ) ! 433: tp->t_rawout.si_ox = 0; ! 434: } ! 435: ! 436: } while ( ++tp <= hslimtty ); ! 437: } ! 438: ! 439: /* ! 440: * Set hardware parameters. ! 441: */ ! 442: gcparam( tp ) ! 443: register TTY * tp; ! 444: { ! 445: register int b; ! 446: int s; ! 447: ! 448: s = sphi(); ! 449: /* ! 450: * Assert required modem control lines (DTR, RTS). ! 451: */ ! 452: b = 0; ! 453: if ( tp->t_sgttyb.sg_ospeed != B0 ) ! 454: b |= MC_DTR | MC_RTS; ! 455: outb( PORT+MCR, b ); ! 456: ! 457: /* ! 458: * Program baud rate. ! 459: */ ! 460: if (b = timeconst[ tp->t_sgttyb.sg_ospeed ]) { ! 461: outb( PORT+LCR, LC_DLAB ); ! 462: outb( PORT+DLL, b ); ! 463: outb( PORT+DLH, b >> 8 ); ! 464: } ! 465: ! 466: /* ! 467: * Program character size, parity. ! 468: */ ! 469: switch ( tp->t_sgttyb.sg_flags & (EVENP|ODDP|RAW) ) { ! 470: case ODDP: b = LC_CS7|LC_PARENB; break; ! 471: case EVENP: b = LC_CS7|LC_PARENB|LC_PAREVEN; break; ! 472: default: b = LC_CS8; break; ! 473: } ! 474: outb( PORT+LCR, b ); ! 475: ! 476: /* ! 477: * Enable Transmit Buffer Empty Interrupts. ! 478: */ ! 479: outb( PORT+IER, IE_TxI ); ! 480: ! 481: spl(s); ! 482: } ! 483: ! 484: /* ! 485: * Start Routine. ! 486: */ ! 487: gcstart( tp ) ! 488: register TTY * tp; ! 489: { ! 490: register int s; ! 491: ! 492: /* ! 493: * Transmit buffer is empty, and raw output buffer is not. ! 494: */ ! 495: s = sphi(); ! 496: if ( (inb( PORT+LSR ) & LS_TxRDY) ! 497: && (tp->t_rawout.si_ix != tp->t_rawout.si_ox) ) { ! 498: ! 499: /* ! 500: * Send next char from raw output buffer. ! 501: */ ! 502: outb( PORT+DREG, tp->t_rawout.si_buf[ tp->t_rawout.si_ox ] ); ! 503: ! 504: if ( ++tp->t_rawout.si_ox >= sizeof(tp->t_rawout.si_buf) ) ! 505: tp->t_rawout.si_ox = 0; ! 506: } ! 507: spl( s ); ! 508: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.