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