|
|
1.1 ! root 1: /* ! 2: * Mach Operating System ! 3: * Copyright (c) 1993-1989 Carnegie Mellon University ! 4: * All Rights Reserved. ! 5: * ! 6: * Permission to use, copy, modify and distribute this software and its ! 7: * documentation is hereby granted, provided that both the copyright ! 8: * notice and this permission notice appear in all copies of the ! 9: * software, derivative works or modified versions, and any portions ! 10: * thereof, and that both notices appear in supporting documentation. ! 11: * ! 12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 15: * ! 16: * Carnegie Mellon requests users of this software to return to ! 17: * ! 18: * Software Distribution Coordinator or [email protected] ! 19: * School of Computer Science ! 20: * Carnegie Mellon University ! 21: * Pittsburgh PA 15213-3890 ! 22: * ! 23: * any improvements or extensions that they make and grant Carnegie Mellon ! 24: * the rights to redistribute these changes. ! 25: */ ! 26: /* ! 27: * File: scc_8530_hdw.c ! 28: * Author: Alessandro Forin, Carnegie Mellon University ! 29: * Date: 6/91 ! 30: * ! 31: * Hardware-level operations for the SCC Serial Line Driver ! 32: */ ! 33: ! 34: #include <scc.h> ! 35: #if NSCC > 0 ! 36: #include <bm.h> ! 37: #include <platforms.h> ! 38: ! 39: #include <mach_kdb.h> ! 40: ! 41: #include <machine/machspl.h> /* spl definitions */ ! 42: #include <mach/std_types.h> ! 43: #include <device/io_req.h> ! 44: #include <device/tty.h> ! 45: ! 46: #include <chips/busses.h> ! 47: #include <chips/serial_defs.h> ! 48: #include <chips/screen_defs.h> ! 49: ! 50: /* Alignment and padding */ ! 51: #if defined(DECSTATION) ! 52: /* ! 53: * 3min's padding ! 54: */ ! 55: typedef struct { ! 56: char pad0; ! 57: volatile unsigned char datum; ! 58: char pad1[2]; ! 59: } scc_padded1_register_t; ! 60: ! 61: #define scc_register_t scc_padded1_register_t ! 62: #endif ! 63: ! 64: #if defined(FLAMINGO) ! 65: typedef struct { ! 66: volatile unsigned int datum; ! 67: unsigned int pad1; ! 68: } scc_padded1_register_t; ! 69: ! 70: #define scc_register_t scc_padded1_register_t ! 71: ! 72: #define scc_set_datum(d,v) (d) = (volatile unsigned int) (v) << 8, wbflush() ! 73: #define scc_get_datum(d,v) (v) = ((d) >> 8) & 0xff ! 74: ! 75: #endif ! 76: ! 77: #include <chips/scc_8530.h> /* needs the above defs */ ! 78: ! 79: #define private static ! 80: #define public ! 81: ! 82: /* ! 83: * Forward decls ! 84: */ ! 85: private check_car( struct tty *, boolean_t ); ! 86: ! 87: /* ! 88: * On the 3min keyboard and mouse come in on channels A ! 89: * of the two units. The MI code expects them at 'lines' ! 90: * 0 and 1, respectively. So we map here back and forth. ! 91: * Note also the MI code believes unit 0 has four lines. ! 92: */ ! 93: ! 94: #define SCC_KBDUNIT 1 ! 95: #define SCC_PTRUNIT 0 ! 96: ! 97: mi_to_scc(unitp, linep) ! 98: int *unitp, *linep; ! 99: { ! 100: /* only play games on MI 'unit' 0 */ ! 101: if (*unitp) { ! 102: /* e.g. by mapping the first four lines specially */ ! 103: *unitp++; ! 104: return; ! 105: } ! 106: ! 107: /* always get unit=0 (console) and line = 0|1 */ ! 108: if (*linep == SCREEN_LINE_KEYBOARD) { ! 109: *unitp = SCC_KBDUNIT; ! 110: *linep = SCC_CHANNEL_A; ! 111: } else if (*linep == SCREEN_LINE_POINTER) { ! 112: *unitp = SCC_PTRUNIT; ! 113: *linep = SCC_CHANNEL_A; ! 114: } else { ! 115: *unitp = (*linep & 1); ! 116: *linep = SCC_CHANNEL_B; ! 117: } ! 118: /* line 0 is channel B, line 1 is channel A */ ! 119: } ! 120: ! 121: #define NSCC_LINE 2 /* 2 ttys per chip */ ! 122: ! 123: /* only care for mapping to ttyno */ ! 124: scc_to_mi(sccunit, sccline) ! 125: { ! 126: if (sccunit > 1) ! 127: return (sccunit * NSCC_LINE + sccline); ! 128: /* only for console (first pair of SCCs): */ ! 129: if (sccline == SCC_CHANNEL_A) ! 130: return ((!sccunit) & 1); ! 131: return 2+sccunit; ! 132: } ! 133: ! 134: ! 135: /* ! 136: * Driver status ! 137: */ ! 138: struct scc_softc { ! 139: scc_regmap_t *regs; ! 140: ! 141: /* software copy of some write regs, for reg |= */ ! 142: struct softreg { ! 143: unsigned char wr1; ! 144: unsigned char wr4; ! 145: unsigned char wr5; ! 146: unsigned char wr14; ! 147: } softr[2]; /* per channel */ ! 148: ! 149: unsigned char last_rr0[2]; /* for modem signals */ ! 150: unsigned short fake; /* missing rs232 bits, channel A */ ! 151: char polling_mode; ! 152: char softCAR, osoftCAR; ! 153: char probed_once; ! 154: ! 155: boolean_t full_modem; ! 156: boolean_t isa_console; ! 157: ! 158: } scc_softc_data[NSCC]; ! 159: ! 160: typedef struct scc_softc *scc_softc_t; ! 161: ! 162: scc_softc_t scc_softc[NSCC]; ! 163: ! 164: scc_softCAR(unit, line, on) ! 165: { ! 166: mi_to_scc(&unit, &line); ! 167: if (on) ! 168: scc_softc[unit]->softCAR |= 1<<line; ! 169: else ! 170: scc_softc[unit]->softCAR &= ~(1 << line); ! 171: } ! 172: ! 173: ! 174: /* ! 175: * BRG formula is: ! 176: * ClockFrequency ! 177: * BRGconstant = --------------------------- - 2 ! 178: * 2 * BaudRate * ClockDivider ! 179: */ ! 180: /* Speed selections with Pclk=7.3728Mhz, clock x16 */ ! 181: static ! 182: short scc_speeds[] = ! 183: /* 0 50 75 110 134.5 150 200 300 600 1200 1800 2400 */ ! 184: { 0, 4606, 3070, 2093, 1711, 1534, 1150, 766, 382, 190, 126, 94, ! 185: ! 186: /* 4800 9600 19.2k 38.4k */ ! 187: 46, 22, 10, 4}; ! 188: ! 189: /* ! 190: * Definition of the driver for the auto-configuration program. ! 191: */ ! 192: ! 193: int scc_probe(), scc_intr(); ! 194: static void scc_attach(); ! 195: ! 196: vm_offset_t scc_std[NSCC] = { 0 }; ! 197: struct bus_device *scc_info[NSCC]; ! 198: struct bus_driver scc_driver = ! 199: { scc_probe, 0, scc_attach, 0, scc_std, "scc", scc_info,}; ! 200: ! 201: /* ! 202: * Adapt/Probe/Attach functions ! 203: */ ! 204: boolean_t scc_uses_modem_control = FALSE;/* patch this with adb */ ! 205: ! 206: set_scc_address( ! 207: int sccunit, ! 208: vm_offset_t regs, ! 209: boolean_t has_modem, ! 210: boolean_t isa_console) ! 211: { ! 212: extern int scc_probe(), scc_param(), scc_start(), ! 213: scc_putc(), scc_getc(), ! 214: scc_pollc(), scc_mctl(), scc_softCAR(); ! 215: ! 216: scc_std[sccunit] = regs; ! 217: scc_softc_data[sccunit].full_modem = has_modem & scc_uses_modem_control; ! 218: scc_softc_data[sccunit].isa_console = isa_console; ! 219: ! 220: /* Do this here */ ! 221: console_probe = scc_probe; ! 222: console_param = scc_param; ! 223: console_start = scc_start; ! 224: console_putc = scc_putc; ! 225: console_getc = scc_getc; ! 226: console_pollc = scc_pollc; ! 227: console_mctl = scc_mctl; ! 228: console_softCAR = scc_softCAR; ! 229: ! 230: } ! 231: ! 232: scc_probe( ! 233: int xxx, ! 234: struct bus_device *ui) ! 235: { ! 236: int sccunit = ui->unit; ! 237: scc_softc_t scc; ! 238: register int val; ! 239: register scc_regmap_t *regs; ! 240: ! 241: regs = (scc_regmap_t *)scc_std[sccunit]; ! 242: if (regs == 0) ! 243: return 0; ! 244: ! 245: /* ! 246: * See if we are here ! 247: */ ! 248: if (check_memory(regs, 0)) { ! 249: /* no rides today */ ! 250: return 0; ! 251: } ! 252: ! 253: scc = &scc_softc_data[sccunit]; ! 254: ! 255: if (scc->probed_once++){ ! 256: return 1; ! 257: } ! 258: /* ! 259: * Chip once-only initialization ! 260: * ! 261: * NOTE: The wiring we assume is the one on the 3min: ! 262: * ! 263: * out A-TxD --> TxD keybd or mouse ! 264: * in A-RxD --> RxD keybd or mouse ! 265: * out A-DTR~ --> DTR comm ! 266: * out A-RTS~ --> RTS comm ! 267: * in A-CTS~ --> SI comm ! 268: * in A-DCD~ --> RI comm ! 269: * in A-SYNCH~--> DSR comm ! 270: * out B-TxD --> TxD comm ! 271: * in B-RxD --> RxD comm ! 272: * in B-RxC --> TRxCB comm ! 273: * in B-TxC --> RTxCB comm ! 274: * out B-RTS~ --> SS comm ! 275: * in B-CTS~ --> CTS comm ! 276: * in B-DCD~ --> CD comm ! 277: */ ! 278: ! 279: scc_softc[sccunit] = scc; ! 280: scc->regs = regs; ! 281: ! 282: scc->fake = 1<<SCC_CHANNEL_A; ! 283: ! 284: { ! 285: register int i; ! 286: /* We need this in scc_start only, hence the funny ! 287: value: we need it non-zero and we want to avoid ! 288: too much overhead in getting to (scc,regs,line) */ ! 289: for (i = 0; i < NSCC_LINE; i++) { ! 290: register struct tty *tp; ! 291: ! 292: tp = console_tty[scc_to_mi(sccunit,i)]; ! 293: tp->t_addr = (char*)(0x80000000L + (sccunit<<1) + (i&1)); ! 294: /* do min buffering */ ! 295: tp->t_state |= TS_MIN; ! 296: } ! 297: } ! 298: ! 299: /* make sure reg pointer is in known state */ ! 300: scc_init_reg(regs, SCC_CHANNEL_A); ! 301: scc_init_reg(regs, SCC_CHANNEL_B); ! 302: ! 303: /* reset chip, fully */ ! 304: scc_write_reg(regs, SCC_CHANNEL_A, SCC_WR9, SCC_WR9_HW_RESET); ! 305: delay(50000);/*enough ? */ ! 306: scc_write_reg(regs, SCC_CHANNEL_A, SCC_WR9, 0); ! 307: ! 308: /* program the interrupt vector */ ! 309: scc_write_reg(regs, SCC_CHANNEL_A, SCC_WR2, 0xf0); ! 310: scc_write_reg(regs, SCC_CHANNEL_B, SCC_WR2, 0xf0); ! 311: scc_write_reg(regs, SCC_CHANNEL_A, SCC_WR9, SCC_WR9_VIS); ! 312: ! 313: /* most of the init is in scc_param() */ ! 314: ! 315: /* timing base defaults */ ! 316: scc->softr[SCC_CHANNEL_A].wr4 = SCC_WR4_CLK_x16; ! 317: scc->softr[SCC_CHANNEL_B].wr4 = SCC_WR4_CLK_x16; ! 318: ! 319: /* enable DTR, RTS and dont SS */ ! 320: #if 0 ! 321: /* According to one book I have this signal (pin 23, "SS") ! 322: is "specified by the provider", meaning the EIA-232-D ! 323: standard does not define what it is. Better leave ! 324: it alone */ ! 325: scc->softr[SCC_CHANNEL_B].wr5 = SCC_WR5_RTS; ! 326: #else ! 327: scc->softr[SCC_CHANNEL_B].wr5 = 0; ! 328: #endif ! 329: scc->softr[SCC_CHANNEL_A].wr5 = SCC_WR5_RTS | SCC_WR5_DTR; ! 330: ! 331: /* baud rates */ ! 332: val = SCC_WR14_BAUDR_ENABLE|SCC_WR14_BAUDR_SRC; ! 333: scc->softr[SCC_CHANNEL_B].wr14 = val; ! 334: scc->softr[SCC_CHANNEL_A].wr14 = val; ! 335: ! 336: /* interrupt conditions */ ! 337: val = SCC_WR1_RXI_ALL_CHAR | SCC_WR1_PARITY_IE | ! 338: SCC_WR1_EXT_IE | SCC_WR1_TX_IE; ! 339: scc->softr[SCC_CHANNEL_A].wr1 = val; ! 340: scc->softr[SCC_CHANNEL_B].wr1 = val; ! 341: ! 342: scc_read_reg_zero(regs, SCC_CHANNEL_A, scc->last_rr0[SCC_CHANNEL_A]); ! 343: scc_read_reg_zero(regs, SCC_CHANNEL_B, scc->last_rr0[SCC_CHANNEL_B]); ! 344: ! 345: /* ! 346: * After probing, any line that should be active ! 347: * (keybd,mouse,rcline) is activated via scc_param(). ! 348: */ ! 349: ! 350: scc_set_modem_control(scc, scc->full_modem); ! 351: ! 352: #if defined(KMIN) || defined (FLAMINGO) || defined(KN03) ! 353: /* ! 354: * Crock: MI code knows of unit 0 as console, we need ! 355: * unit 1 as well since the keyboard is there ! 356: * This is acceptable on maxine, which has to call its ! 357: * only one chip unit 1 so that rconsole is happy. ! 358: */ ! 359: if (sccunit == 0) { ! 360: struct bus_device d; ! 361: d = *ui; ! 362: d.unit = 1; ! 363: scc_probe( xxx, &d); ! 364: } ! 365: #endif ! 366: return 1; ! 367: } ! 368: ! 369: boolean_t scc_timer_started = FALSE; ! 370: ! 371: static void ! 372: scc_attach( ! 373: register struct bus_device *ui) ! 374: { ! 375: int sccunit = ui->unit; ! 376: extern scc_scan(); ! 377: extern int tty_inq_size; ! 378: int i; ! 379: ! 380: /* We only have 4 ttys, but always at 9600 ! 381: * Give em a lot of room (plus dma..) ! 382: */ ! 383: tty_inq_size = 4096; ! 384: if (!scc_timer_started) { ! 385: /* do all of them, before we call scc_scan() */ ! 386: /* harmless if done already */ ! 387: for (i = 0; i < NSCC*NSCC_LINE; i++) ! 388: ttychars(console_tty[i]); ! 389: ! 390: scc_timer_started = TRUE; ! 391: scc_scan(); ! 392: } ! 393: ! 394: #if NBM > 0 ! 395: if (SCREEN_ISA_CONSOLE() && scc_softc[sccunit]->isa_console) { ! 396: printf("\n sl0: "); ! 397: if (sccunit && rcline == 3) printf("( rconsole )"); ! 398: ! 399: if (sccunit == SCC_KBDUNIT) { ! 400: printf("\n sl1: "); lk201_attach(0, sccunit >> 1); ! 401: } else if (sccunit == SCC_PTRUNIT) { ! 402: printf("\n sl1: "); mouse_attach(0, sccunit >> 1); ! 403: } ! 404: } else ! 405: #endif /*NBM > 0*/ ! 406: { ! 407: printf("%s", (sccunit == 1) ? ! 408: "\n sl0: ( alternate console )\n sl1:" : ! 409: "\n sl0:\n sl1:"); ! 410: } ! 411: } ! 412: ! 413: /* ! 414: * Would you like to make a phone call ? ! 415: */ ! 416: scc_set_modem_control( ! 417: scc_softc_t scc, ! 418: boolean_t on) ! 419: { ! 420: if (on) ! 421: /* your problem if the hardware then is broke */ ! 422: scc->fake = 0; ! 423: else ! 424: scc->fake = 3; ! 425: scc->full_modem = on; ! 426: /* user should do an scc_param() ifchanged */ ! 427: } ! 428: ! 429: /* ! 430: * Polled I/O (debugger) ! 431: */ ! 432: scc_pollc( ! 433: int unit, ! 434: boolean_t on) ! 435: { ! 436: scc_softc_t scc; ! 437: int line = SCREEN_LINE_KEYBOARD, ! 438: sccunit = unit; ! 439: ! 440: mi_to_scc(&sccunit, &line); ! 441: ! 442: scc = scc_softc[sccunit]; ! 443: if (on) { ! 444: scc->polling_mode++; ! 445: #if NBM > 0 ! 446: screen_on_off(unit, TRUE); ! 447: #endif NBM > 0 ! 448: } else ! 449: scc->polling_mode--; ! 450: } ! 451: ! 452: /* ! 453: * Interrupt routine ! 454: */ ! 455: int scc_intr_count; ! 456: ! 457: scc_intr( ! 458: int unit, ! 459: spl_t spllevel) ! 460: { ! 461: scc_softc_t scc = scc_softc[unit]; ! 462: register scc_regmap_t *regs = scc->regs; ! 463: register int rr1, rr2; ! 464: register int c; ! 465: ! 466: scc_intr_count++; ! 467: ! 468: #if mips ! 469: splx(spllevel); /* lower priority */ ! 470: #endif ! 471: ! 472: while (1) { ! 473: ! 474: scc_read_reg(regs, SCC_CHANNEL_B, SCC_RR2, rr2); ! 475: ! 476: rr2 = SCC_RR2_STATUS(rr2); ! 477: ! 478: /* are we done yet ? */ ! 479: if (rr2 == 6) { /* strange, distinguished value */ ! 480: register int rr3; ! 481: scc_read_reg(regs, SCC_CHANNEL_A, SCC_RR3, rr3); ! 482: if (rr3 == 0) ! 483: return; ! 484: } ! 485: ! 486: if ((rr2 == SCC_RR2_A_XMIT_DONE) || (rr2 == SCC_RR2_B_XMIT_DONE)) { ! 487: ! 488: register chan = (rr2 == SCC_RR2_A_XMIT_DONE) ? ! 489: SCC_CHANNEL_A : SCC_CHANNEL_B; ! 490: ! 491: scc_write_reg(regs, SCC_CHANNEL_A, SCC_RR0, SCC_RESET_HIGHEST_IUS); ! 492: c = cons_simple_tint(scc_to_mi(unit,chan), FALSE); ! 493: ! 494: if (c == -1) { ! 495: /* no more data for this line */ ! 496: ! 497: scc_read_reg(regs, chan, SCC_RR15, c); ! 498: c &= ~SCC_WR15_TX_UNDERRUN_IE; ! 499: scc_write_reg(regs, chan, SCC_WR15, c); ! 500: ! 501: c = scc->softr[chan].wr1 & ~SCC_WR1_TX_IE; ! 502: scc_write_reg(regs, chan, SCC_WR1, c); ! 503: scc->softr[chan].wr1 = c; ! 504: ! 505: c = cons_simple_tint(scc_to_mi(unit,chan), TRUE); ! 506: if (c != -1) ! 507: /* funny race, scc_start has been called already */ ! 508: scc_write_data(regs, chan, c); ! 509: } else { ! 510: scc_write_data(regs, chan, c); ! 511: /* and leave it enabled */ ! 512: } ! 513: } ! 514: ! 515: else if (rr2 == SCC_RR2_A_RECV_DONE) { ! 516: int err = 0; ! 517: ! 518: scc_write_reg(regs, SCC_CHANNEL_A, SCC_RR0, SCC_RESET_HIGHEST_IUS); ! 519: if (scc->polling_mode) ! 520: continue; ! 521: ! 522: scc_read_data(regs, SCC_CHANNEL_A, c); ! 523: rr1 = scc_to_mi(unit,SCC_CHANNEL_A); ! 524: cons_simple_rint (rr1, rr1, c, 0); ! 525: } ! 526: ! 527: else if (rr2 == SCC_RR2_B_RECV_DONE) { ! 528: int err = 0; ! 529: ! 530: scc_write_reg(regs, SCC_CHANNEL_A, SCC_RR0, SCC_RESET_HIGHEST_IUS); ! 531: if (scc->polling_mode) ! 532: continue; ! 533: ! 534: scc_read_data(regs, SCC_CHANNEL_B, c); ! 535: rr1 = scc_to_mi(unit,SCC_CHANNEL_B); ! 536: cons_simple_rint (rr1, rr1, c, 0); ! 537: } ! 538: ! 539: else if ((rr2 == SCC_RR2_A_EXT_STATUS) || (rr2 == SCC_RR2_B_EXT_STATUS)) { ! 540: int chan = (rr2 == SCC_RR2_A_EXT_STATUS) ? ! 541: SCC_CHANNEL_A : SCC_CHANNEL_B; ! 542: scc_write_reg(regs, chan, SCC_RR0, SCC_RESET_EXT_IP); ! 543: scc_write_reg(regs, SCC_CHANNEL_A, SCC_RR0, SCC_RESET_HIGHEST_IUS); ! 544: scc_modem_intr(scc, chan, unit); ! 545: } ! 546: ! 547: else if ((rr2 == SCC_RR2_A_RECV_SPECIAL) || (rr2 == SCC_RR2_B_RECV_SPECIAL)) { ! 548: register int chan = (rr2 == SCC_RR2_A_RECV_SPECIAL) ? ! 549: SCC_CHANNEL_A : SCC_CHANNEL_B; ! 550: ! 551: scc_read_reg(regs, chan, SCC_RR1, rr1); ! 552: if (rr1 & (SCC_RR1_PARITY_ERR | SCC_RR1_RX_OVERRUN | SCC_RR1_FRAME_ERR)) { ! 553: int err; ! 554: /* map to CONS_ERR_xxx MI error codes */ ! 555: err = ((rr1 & SCC_RR1_PARITY_ERR)<<8) | ! 556: ((rr1 & SCC_RR1_RX_OVERRUN)<<9) | ! 557: ((rr1 & SCC_RR1_FRAME_ERR)<<7); ! 558: scc_write_reg(regs, chan, SCC_RR0, SCC_RESET_ERROR); ! 559: rr1 = scc_to_mi(unit,chan); ! 560: cons_simple_rint(rr1, rr1, 0, err); ! 561: } ! 562: scc_write_reg(regs, SCC_CHANNEL_A, SCC_RR0, SCC_RESET_HIGHEST_IUS); ! 563: } ! 564: ! 565: } ! 566: ! 567: } ! 568: ! 569: boolean_t ! 570: scc_start( ! 571: struct tty *tp) ! 572: { ! 573: register scc_regmap_t *regs; ! 574: register int chan, temp; ! 575: register struct softreg *sr; ! 576: ! 577: temp = (natural_t)tp->t_addr; ! 578: chan = (temp & 1); /* channel */ ! 579: temp = (temp >> 1)&0xff;/* sccunit */ ! 580: regs = scc_softc[temp]->regs; ! 581: sr = &scc_softc[temp]->softr[chan]; ! 582: ! 583: scc_read_reg(regs, chan, SCC_RR15, temp); ! 584: temp |= SCC_WR15_TX_UNDERRUN_IE; ! 585: scc_write_reg(regs, chan, SCC_WR15, temp); ! 586: ! 587: temp = sr->wr1 | SCC_WR1_TX_IE; ! 588: scc_write_reg(regs, chan, SCC_WR1, temp); ! 589: sr->wr1 = temp; ! 590: ! 591: /* but we need a first char out or no cookie */ ! 592: scc_read_reg(regs, chan, SCC_RR0, temp); ! 593: if (temp & SCC_RR0_TX_EMPTY) ! 594: { ! 595: register char c; ! 596: ! 597: c = getc(&tp->t_outq); ! 598: scc_write_data(regs, chan, c); ! 599: } ! 600: } ! 601: ! 602: /* ! 603: * Get a char from a specific SCC line ! 604: * [this is only used for console&screen purposes] ! 605: */ ! 606: scc_getc( ! 607: int unit, ! 608: int line, ! 609: boolean_t wait, ! 610: boolean_t raw) ! 611: { ! 612: scc_softc_t scc; ! 613: register scc_regmap_t *regs; ! 614: unsigned char c; ! 615: int value, mi_line, rcvalue, from_line; ! 616: ! 617: mi_line = line; ! 618: mi_to_scc(&unit, &line); ! 619: ! 620: scc = scc_softc[unit]; ! 621: regs = scc->regs; ! 622: ! 623: /* ! 624: * wait till something available ! 625: * ! 626: * NOTE: we know! that rcline==3 ! 627: */ ! 628: if (rcline) rcline = 3; ! 629: again: ! 630: rcvalue = 0; ! 631: while (1) { ! 632: scc_read_reg_zero(regs, line, value); ! 633: if (rcline && (mi_line == SCREEN_LINE_KEYBOARD)) { ! 634: scc_read_reg_zero(regs, SCC_CHANNEL_B, rcvalue); ! 635: value |= rcvalue; ! 636: } ! 637: if (((value & SCC_RR0_RX_AVAIL) == 0) && wait) ! 638: delay(10); ! 639: else ! 640: break; ! 641: } ! 642: ! 643: /* ! 644: * if nothing found return -1 ! 645: */ ! 646: from_line = (rcvalue & SCC_RR0_RX_AVAIL) ? SCC_CHANNEL_B : line; ! 647: ! 648: if (value & SCC_RR0_RX_AVAIL) { ! 649: scc_read_reg(regs, from_line, SCC_RR1, value); ! 650: scc_read_data(regs, from_line, c); ! 651: } else { ! 652: /* splx(s);*/ ! 653: return -1; ! 654: } ! 655: ! 656: /* ! 657: * bad chars not ok ! 658: */ ! 659: if (value&(SCC_RR1_PARITY_ERR | SCC_RR1_RX_OVERRUN | SCC_RR1_FRAME_ERR)) { ! 660: /* scc_state(unit,from_line); */ ! 661: scc_write_reg(regs, from_line, SCC_RR0, SCC_RESET_ERROR); ! 662: if (wait) { ! 663: scc_write_reg(regs, SCC_CHANNEL_A, SCC_RR0, SCC_RESET_HIGHEST_IUS); ! 664: goto again; ! 665: } ! 666: } ! 667: scc_write_reg(regs, SCC_CHANNEL_A, SCC_RR0, SCC_RESET_HIGHEST_IUS); ! 668: /* splx(s);*/ ! 669: ! 670: ! 671: #if NBM > 0 ! 672: if ((mi_line == SCREEN_LINE_KEYBOARD) && (from_line == SCC_CHANNEL_A) && ! 673: !raw && SCREEN_ISA_CONSOLE() && scc->isa_console) ! 674: return lk201_rint(SCREEN_CONS_UNIT(), c, wait, scc->polling_mode); ! 675: else ! 676: #endif NBM > 0 ! 677: return c; ! 678: } ! 679: ! 680: /* ! 681: * Put a char on a specific SCC line ! 682: */ ! 683: scc_putc( ! 684: int unit, ! 685: int line, ! 686: int c) ! 687: { ! 688: scc_softc_t scc; ! 689: register scc_regmap_t *regs; ! 690: spl_t s = spltty(); ! 691: register int value; ! 692: ! 693: mi_to_scc(&unit, &line); ! 694: ! 695: scc = scc_softc[unit]; ! 696: regs = scc->regs; ! 697: ! 698: do { ! 699: scc_read_reg(regs, line, SCC_RR0, value); ! 700: if (value & SCC_RR0_TX_EMPTY) ! 701: break; ! 702: delay(100); ! 703: } while (1); ! 704: ! 705: scc_write_data(regs, line, c); ! 706: /* wait for it to swallow the char ? */ ! 707: ! 708: splx(s); ! 709: } ! 710: ! 711: scc_param( ! 712: struct tty *tp, ! 713: int line) ! 714: { ! 715: scc_regmap_t *regs; ! 716: int value, sccline, unit; ! 717: struct softreg *sr; ! 718: scc_softc_t scc; ! 719: ! 720: line = tp->t_dev; ! 721: /* MI code wants us to handle 4 lines on unit 0 */ ! 722: unit = (line < 4) ? 0 : (line / NSCC_LINE); ! 723: sccline = line; ! 724: mi_to_scc(&unit, &sccline); ! 725: ! 726: if ((scc = scc_softc[unit]) == 0) return; /* sanity */ ! 727: regs = scc->regs; ! 728: ! 729: sr = &scc->softr[sccline]; ! 730: ! 731: /* ! 732: * Do not let user fool around with kbd&mouse ! 733: */ ! 734: #if NBM > 0 ! 735: if (screen_captures(line)) { ! 736: tp->t_ispeed = tp->t_ospeed = B4800; ! 737: tp->t_flags |= TF_LITOUT; ! 738: } ! 739: #endif NBM > 0 ! 740: ! 741: if (tp->t_ispeed == 0) { ! 742: (void) scc_mctl(tp->t_dev, TM_HUP, DMSET); /* hang up line */ ! 743: return; ! 744: } ! 745: ! 746: /* reset line */ ! 747: value = (sccline == SCC_CHANNEL_A) ? SCC_WR9_RESET_CHA_A : SCC_WR9_RESET_CHA_B; ! 748: scc_write_reg(regs, sccline, SCC_WR9, value); ! 749: delay(25); ! 750: ! 751: /* stop bits, normally 1 */ ! 752: value = sr->wr4 & 0xf0; ! 753: value |= (tp->t_ispeed == B110) ? SCC_WR4_2_STOP : SCC_WR4_1_STOP; ! 754: ! 755: /* .. and parity */ ! 756: if ((tp->t_flags & (TF_ODDP | TF_EVENP)) == TF_ODDP) ! 757: value |= SCC_WR4_PARITY_ENABLE; ! 758: ! 759: /* set it now, remember it must be first after reset */ ! 760: sr->wr4 = value; ! 761: scc_write_reg(regs, sccline, SCC_WR4, value); ! 762: ! 763: /* vector again */ ! 764: scc_write_reg(regs, sccline, SCC_WR2, 0xf0); ! 765: ! 766: /* we only do 8 bits per char */ ! 767: value = SCC_WR3_RX_8_BITS; ! 768: scc_write_reg(regs, sccline, SCC_WR3, value); ! 769: ! 770: /* clear break, keep rts dtr */ ! 771: value = sr->wr5 & (SCC_WR5_DTR|SCC_WR5_RTS); ! 772: value |= SCC_WR5_TX_8_BITS; ! 773: sr->wr5 = value; ! 774: scc_write_reg(regs, sccline, SCC_WR5, value); ! 775: /* some are on the other channel, which might ! 776: never be used (e.g. maxine has only one line) */ ! 777: { ! 778: register int otherline = (sccline+1)&1; ! 779: ! 780: scc_write_reg(regs, otherline, SCC_WR5, scc->softr[otherline].wr5); ! 781: } ! 782: ! 783: scc_write_reg(regs, sccline, SCC_WR6, 0); ! 784: scc_write_reg(regs, sccline, SCC_WR7, 0); ! 785: ! 786: scc_write_reg(regs, sccline, SCC_WR9, SCC_WR9_VIS); ! 787: ! 788: scc_write_reg(regs, sccline, SCC_WR10, 0); ! 789: ! 790: /* clock config */ ! 791: value = SCC_WR11_RCLK_BAUDR | SCC_WR11_XTLK_BAUDR | ! 792: SCC_WR11_TRc_OUT | SCC_WR11_TRcOUT_BAUDR; ! 793: scc_write_reg(regs, sccline, SCC_WR11, value); ! 794: ! 795: value = scc_speeds[tp->t_ispeed]; ! 796: scc_set_timing_base(regs,sccline,value); ! 797: ! 798: value = sr->wr14; ! 799: scc_write_reg(regs, sccline, SCC_WR14, value); ! 800: ! 801: #if FLAMINGO ! 802: if (unit != 1) ! 803: #else ! 804: if (1) ! 805: #endif ! 806: { ! 807: /* Chan-A: CTS==SI DCD==RI DSR=SYNCH */ ! 808: value = SCC_WR15_CTS_IE | SCC_WR15_DCD_IE | SCC_WR15_SYNCHUNT_IE; ! 809: scc_write_reg(regs, SCC_CHANNEL_A, SCC_WR15, value); ! 810: ! 811: /* Chan-B: CTS==CTS DCD==DCD */ ! 812: value = SCC_WR15_BREAK_IE | SCC_WR15_CTS_IE | SCC_WR15_DCD_IE; ! 813: scc_write_reg(regs, SCC_CHANNEL_B, SCC_WR15, value); ! 814: } else { ! 815: /* Here if modem bits are floating noise, keep quiet */ ! 816: value = SCC_WR15_BREAK_IE; ! 817: scc_write_reg(regs, sccline, SCC_WR15, value); ! 818: } ! 819: ! 820: /* and now the enables */ ! 821: value = SCC_WR3_RX_8_BITS | SCC_WR3_RX_ENABLE; ! 822: scc_write_reg(regs, sccline, SCC_WR3, value); ! 823: ! 824: value = sr->wr5 | SCC_WR5_TX_ENABLE; ! 825: sr->wr5 = value; ! 826: scc_write_reg(regs, sccline, SCC_WR5, value); ! 827: ! 828: /* master inter enable */ ! 829: scc_write_reg(regs,sccline,SCC_WR9,SCC_WR9_MASTER_IE|SCC_WR9_VIS); ! 830: ! 831: scc_write_reg(regs, sccline, SCC_WR1, sr->wr1); ! 832: ! 833: } ! 834: ! 835: /* ! 836: * Modem control functions ! 837: */ ! 838: scc_mctl( ! 839: int dev, ! 840: int bits, ! 841: int how) ! 842: { ! 843: register scc_regmap_t *regs; ! 844: struct softreg *sra, *srb, *sr; ! 845: int unit, sccline; ! 846: int b = 0; ! 847: spl_t s; ! 848: scc_softc_t scc; ! 849: ! 850: /* MI code wants us to handle 4 lines on unit 0 */ ! 851: unit = (dev < 4) ? 0 : (dev / NSCC_LINE); ! 852: sccline = dev; ! 853: mi_to_scc(&unit, &sccline); ! 854: ! 855: if ((scc = scc_softc[unit]) == 0) return 0; /* sanity */ ! 856: regs = scc->regs; ! 857: ! 858: sr = &scc->softr[sccline]; ! 859: sra = &scc->softr[SCC_CHANNEL_A]; ! 860: srb = &scc->softr[SCC_CHANNEL_B]; ! 861: ! 862: if (bits == TM_HUP) { /* close line (internal) */ ! 863: bits = TM_DTR | TM_RTS; ! 864: how = DMBIC; ! 865: /* xxx interrupts too ?? */ ! 866: } ! 867: ! 868: if (bits & TM_BRK) { ! 869: switch (how) { ! 870: case DMSET: ! 871: case DMBIS: ! 872: sr->wr5 |= SCC_WR5_SEND_BREAK; ! 873: break; ! 874: case DMBIC: ! 875: sr->wr5 &= ~SCC_WR5_SEND_BREAK; ! 876: break; ! 877: default: ! 878: goto dontbrk; ! 879: } ! 880: s = spltty(); ! 881: scc_write_reg(regs, sccline, SCC_WR5, sr->wr5); ! 882: splx(s); ! 883: dontbrk: ! 884: b |= (sr->wr5 & SCC_WR5_SEND_BREAK) ? TM_BRK : 0; ! 885: } ! 886: ! 887: /* no modem support on channel A */ ! 888: if (sccline == SCC_CHANNEL_A) ! 889: return (b | TM_LE | TM_DTR | TM_CTS | TM_CAR | TM_DSR); ! 890: ! 891: sra = &scc->softr[SCC_CHANNEL_A]; ! 892: srb = &scc->softr[SCC_CHANNEL_B]; ! 893: ! 894: #if 0 ! 895: /* do I need to do something on this ? */ ! 896: if (bits & TM_LE) { /* line enable */ ! 897: } ! 898: #endif ! 899: ! 900: if (bits & (TM_DTR|TM_RTS)) { /* data terminal ready, request to send */ ! 901: register int w = 0; ! 902: ! 903: if (bits & TM_DTR) w |= SCC_WR5_DTR; ! 904: if (bits & TM_RTS) w |= SCC_WR5_RTS; ! 905: ! 906: switch (how) { ! 907: case DMSET: ! 908: case DMBIS: ! 909: sra->wr5 |= w; ! 910: break; ! 911: case DMBIC: ! 912: sra->wr5 &= ~w; ! 913: break; ! 914: default: ! 915: goto dontdtr; ! 916: } ! 917: s = spltty(); ! 918: scc_write_reg(regs, SCC_CHANNEL_A, SCC_WR5, sra->wr5); ! 919: splx(s); ! 920: dontdtr: ! 921: b |= (sra->wr5 & w) ? (bits & (TM_DTR|TM_RTS)) : 0; ! 922: } ! 923: ! 924: s = spltty(); ! 925: ! 926: #if 0 ! 927: /* Unsupported */ ! 928: if (bits & TM_ST) { /* secondary transmit */ ! 929: } ! 930: if (bits & TM_SR) { /* secondary receive */ ! 931: } ! 932: #endif ! 933: ! 934: if (bits & TM_CTS) { /* clear to send */ ! 935: register int value; ! 936: scc_read_reg(regs, SCC_CHANNEL_B, SCC_RR0, value); ! 937: b |= (value & SCC_RR0_CTS) ? TM_CTS : 0; ! 938: } ! 939: ! 940: if (bits & TM_CAR) { /* carrier detect */ ! 941: register int value; ! 942: scc_read_reg(regs, SCC_CHANNEL_B, SCC_RR0, value); ! 943: b |= (value & SCC_RR0_DCD) ? TM_CAR : 0; ! 944: } ! 945: ! 946: if (bits & TM_RNG) { /* ring */ ! 947: register int value; ! 948: scc_read_reg(regs, SCC_CHANNEL_A, SCC_RR0, value); ! 949: b |= (value & SCC_RR0_DCD) ? TM_RNG : 0; ! 950: } ! 951: ! 952: if (bits & TM_DSR) { /* data set ready */ ! 953: register int value; ! 954: scc_read_reg(regs, SCC_CHANNEL_A, SCC_RR0, value); ! 955: b |= (value & SCC_RR0_SYNCH) ? TM_DSR : 0; ! 956: } ! 957: ! 958: splx(s); ! 959: ! 960: return b; ! 961: } ! 962: ! 963: #define debug 0 ! 964: ! 965: scc_modem_intr( ! 966: scc_softc_t scc, ! 967: int chan, ! 968: int unit) ! 969: { ! 970: register int value, changed; ! 971: ! 972: scc_read_reg_zero(scc->regs, chan, value); ! 973: ! 974: /* See what changed */ ! 975: changed = value ^ scc->last_rr0[chan]; ! 976: scc->last_rr0[chan] = value; ! 977: ! 978: #if debug ! 979: printf("sccmodem: chan %c now %x, changed %x : ", ! 980: (chan == SCC_CHANNEL_B) ? 'B' : 'A', ! 981: value, changed); ! 982: #endif ! 983: ! 984: if (chan == SCC_CHANNEL_A) { ! 985: if (changed & SCC_RR0_CTS) { ! 986: /* Speed indicator, ignore XXX */ ! 987: #if debug ! 988: printf("%s-speed ", (value & SCC_RR0_CTS) ? "Full" : "Half"); ! 989: #endif ! 990: } ! 991: if (changed & SCC_RR0_DCD) { ! 992: /* Ring indicator */ ! 993: #if debug ! 994: printf("Ring "); ! 995: #endif ! 996: } ! 997: if (changed & SCC_RR0_SYNCH) { ! 998: /* Data Set Ready */ ! 999: #if debug ! 1000: printf("DSR "); ! 1001: #endif ! 1002: /* If modem went down then CD will also go down, ! 1003: or it did already. ! 1004: If modem came up then we have to wait for CD ! 1005: anyways before enabling the line. ! 1006: Either way, nothing to do here */ ! 1007: } ! 1008: } else { ! 1009: if (changed & SCC_RR0_CTS) { ! 1010: /* Clear To Send */ ! 1011: #if debug ! 1012: printf("CTS "); ! 1013: #endif ! 1014: tty_cts(console_tty[scc_to_mi(unit,chan)], ! 1015: value & SCC_RR0_CTS); ! 1016: } ! 1017: if (changed & SCC_RR0_DCD) { ! 1018: #if debug ! 1019: printf("CD "); ! 1020: #endif ! 1021: check_car(console_tty[scc_to_mi(unit,chan)], ! 1022: value & SCC_RR0_DCD); ! 1023: } ! 1024: } ! 1025: #if debug ! 1026: printf(".\n"); ! 1027: #endif ! 1028: } ! 1029: ! 1030: private check_car( ! 1031: register struct tty *tp, ! 1032: boolean_t car) ! 1033: ! 1034: { ! 1035: if (car) { ! 1036: #if notyet ! 1037: /* cancel modem timeout if need to */ ! 1038: if (car & (SCC_MSR_CD2 | SCC_MSR_CD3)) ! 1039: untimeout(scc_hup, (vm_offset_t)tp); ! 1040: #endif ! 1041: ! 1042: /* I think this belongs in the MI code */ ! 1043: if (tp->t_state & TS_WOPEN) ! 1044: tp->t_state |= TS_ISOPEN; ! 1045: /* carrier present */ ! 1046: if ((tp->t_state & TS_CARR_ON) == 0) ! 1047: (void)ttymodem(tp, 1); ! 1048: } else if ((tp->t_state&TS_CARR_ON) && ttymodem(tp, 0) == 0) ! 1049: scc_mctl( tp->t_dev, TM_DTR, DMBIC); ! 1050: } ! 1051: ! 1052: /* ! 1053: * Periodically look at the CD signals: ! 1054: * they do generate interrupts but we ! 1055: * must fake them on channel A. We might ! 1056: * also fake them on channel B. ! 1057: */ ! 1058: scc_scan() ! 1059: { ! 1060: register i; ! 1061: spl_t s = spltty(); ! 1062: ! 1063: for (i = 0; i < NSCC; i++) { ! 1064: register scc_softc_t scc; ! 1065: register int car; ! 1066: register struct tty **tpp; ! 1067: ! 1068: scc = scc_softc[i]; ! 1069: if (scc == 0) ! 1070: continue; ! 1071: car = scc->softCAR | scc->fake; ! 1072: ! 1073: tpp = &console_tty[i * NSCC_LINE]; ! 1074: ! 1075: while (car) { ! 1076: if (car & 1) ! 1077: check_car(*tpp, 1); ! 1078: tpp++; ! 1079: car = car>>1; ! 1080: } ! 1081: ! 1082: } ! 1083: splx(s); ! 1084: timeout(scc_scan, (vm_offset_t)0, 5*hz); ! 1085: } ! 1086: ! 1087: ! 1088: #if debug ! 1089: scc_rr0(unit,chan) ! 1090: { ! 1091: int val; ! 1092: scc_read_reg_zero(scc_softc[unit]->regs, chan, val); ! 1093: return val; ! 1094: } ! 1095: ! 1096: scc_rreg(unit,chan,n) ! 1097: { ! 1098: int val; ! 1099: scc_read_reg(scc_softc[unit]->regs, chan, n, val); ! 1100: return val; ! 1101: } ! 1102: ! 1103: scc_wreg(unit,chan,n,val) ! 1104: { ! 1105: scc_write_reg(scc_softc[unit]->regs, chan, n, val); ! 1106: } ! 1107: ! 1108: scc_state(unit,soft) ! 1109: { ! 1110: int rr0, rr1, rr3, rr12, rr13, rr15; ! 1111: ! 1112: rr0 = scc_rreg(unit, SCC_CHANNEL_A, SCC_RR0); ! 1113: rr1 = scc_rreg(unit, SCC_CHANNEL_A, SCC_RR1); ! 1114: rr3 = scc_rreg(unit, SCC_CHANNEL_A, SCC_RR3); ! 1115: rr12 = scc_rreg(unit, SCC_CHANNEL_A, SCC_RR12); ! 1116: rr13 = scc_rreg(unit, SCC_CHANNEL_A, SCC_RR13); ! 1117: rr15 = scc_rreg(unit, SCC_CHANNEL_A, SCC_RR15); ! 1118: printf("{%d intr, A: R0 %x R1 %x R3 %x baudr %x R15 %x}\n", ! 1119: scc_intr_count, rr0, rr1, rr3, ! 1120: (rr13 << 8) | rr12, rr15); ! 1121: ! 1122: rr0 = scc_rreg(unit, SCC_CHANNEL_B, SCC_RR0); ! 1123: rr1 = scc_rreg(unit, SCC_CHANNEL_B, SCC_RR1); ! 1124: rr3 = scc_rreg(unit, SCC_CHANNEL_B, SCC_RR2); ! 1125: rr12 = scc_rreg(unit, SCC_CHANNEL_B, SCC_RR12); ! 1126: rr13 = scc_rreg(unit, SCC_CHANNEL_B, SCC_RR13); ! 1127: rr15 = scc_rreg(unit, SCC_CHANNEL_B, SCC_RR15); ! 1128: printf("{B: R0 %x R1 %x R2 %x baudr %x R15 %x}\n", ! 1129: rr0, rr1, rr3, ! 1130: (rr13 << 8) | rr12, rr15); ! 1131: ! 1132: if (soft) { ! 1133: struct softreg *sr; ! 1134: sr = scc_softc[unit]->softr; ! 1135: printf("{B: W1 %x W4 %x W5 %x W14 %x}", ! 1136: sr->wr1, sr->wr4, sr->wr5, sr->wr14); ! 1137: sr++; ! 1138: printf("{A: W1 %x W4 %x W5 %x W14 %x}\n", ! 1139: sr->wr1, sr->wr4, sr->wr5, sr->wr14); ! 1140: } ! 1141: } ! 1142: ! 1143: #endif ! 1144: ! 1145: #endif NSCC > 0
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.