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