|
|
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.