4.4BSD snapshot (revision 8.1); add 1993 to copyright
[unix-history] / usr / src / sys / news3400 / sio / scc.c
CommitLineData
af5295ff 1/*
9c147255
KB
2 * Copyright (c) 1992, 1993
3 * The Regents of the University of California. All rights reserved.
af5295ff
KM
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Sony Corp. and Kazumasa Utashiro of Software Research Associates, Inc.
7 *
8 * %sccs.include.redist.c%
9 *
10 * from: $Hdr: scc.c,v 4.300 91/06/09 06:44:53 root Rel41 $ SONY
11 *
9c147255 12 * @(#)scc.c 8.1 (Berkeley) %G%
af5295ff
KM
13 */
14
15/*
16 * LH8530 SCC (serial communication controller) driver
17 *
18 * NOTE: This driver is available only for news700/1200/1700/3400.
19 *
20 * Any code and mechanism in this module may not be used
21 * in any form without permissions. COPYRIGHT (C) 1989-
22 * SONY Corporation, Super Microsystems Group (SMSG),
23 * Work Station Division, all rights RESERVED.
24 */
25
5b7c2955 26#include <machine/adrsmap.h>
af5295ff 27
af5295ff 28#include "rs.h"
af5295ff 29
5b7c2955
KU
30#include <sys/param.h>
31#include <sys/ioctl.h>
32#include <sys/tty.h>
33#include <sys/malloc.h>
af5295ff 34
5b7c2955
KU
35#include <news3400/sio/sccparam.h>
36#include <news3400/sio/sccreg.h>
37#include <news3400/sio/scc.h>
38#include <news3400/sio/scc.conf>
af5295ff
KM
39
40#define PROBE_DATA 0x55
41
42#ifdef mips
43#define VOLATILE volatile
44#else
45#define VOLATILE
46#endif
47
48int tty00_is_console = 0;
49
50#define SCC_BUFSIZE 256
51
52char scc_buf[2][SCC_BUFSIZE];
53
54scc_open(chan)
55 int chan;
56{
57 register Scc_channel *scc = &sccsw[chan];
58 register int s;
59
60 s = splscc();
61 if ((scc->scc_status & CHAN_ACTIVE) == 0) {
62 scc_init(chan);
63 if (chan <= SCC_REMOTE1)
64 scc->r_dma.dma_addr = scc_buf[chan];
65 else
66 scc->r_dma.dma_addr =
67 malloc(SCC_BUFSIZE, M_DEVBUF, M_WAITOK);
68 scc->r_dma.dma_count = 0;
69 scc->scc_status |= CHAN_ACTIVE;
70 }
71 (void) splx(s);
72 return (0);
73}
74
75scc_probe(chan)
76 register int chan;
77{
78 VOLATILE struct scc_reg *port = sccsw[chan].scc_port;
79 int s, temp, probe;
80
81 if (badaddr(port, 1))
82 return (0);
83 s = splscc();
84 temp = scc_read_reg(chan, RR12);
85 scc_write_reg(chan, WR12, PROBE_DATA);
86 probe = scc_read_reg(chan, RR12);
87 scc_write_reg(chan, WR12, temp);
88 (void) splx(s);
89 return (probe == PROBE_DATA);
90}
91
92scc_getc(chan)
93 int chan;
94{
95 VOLATILE struct scc_reg *port = sccsw[chan].scc_port;
96 int c;
97
98 if (port->ctrl & R0_RxCA) {
99 SCCWAIT;
100 c = port->data;
101 SCCWAIT;
102 return (c);
103 }
104 SCCWAIT;
105 return (-1);
106}
107
108#ifndef notdef
109scc_putc(chan, c)
110 int chan, c;
111{
112 register VOLATILE struct scc_reg *port = sccsw[chan].scc_port;
113
114 while ((port->ctrl & R0_TxBE) == 0)
115 SCCWAIT;
116 SCCWAIT;
117 port->data = c;
118 SCCWAIT;
119}
120#else
121scc_putc(chan, c)
122 int chan, c;
123{
124 register VOLATILE struct scc_reg *port = sccsw[chan].scc_port;
125 register VOLATILE u_char *ctrl = &sccsw[chan].scc_port->ctrl;
126 register VOLATILE u_char *data = &sccsw[chan].scc_port->data;
127
128 SCCWAIT;
129 while ((*ctrl & R0_TxBE) == 0) {
130 SCCWAIT;
131 }
132 SCCWAIT;
133
134 *ctrl = W0_RES_TxINT;
135 SCCWAIT;
136 *data = (char)(c & 0xff);
137 SCCWAIT;
138 scc_write_reg(chan, WR1, W1_RxINT_ALL|W1_TxINTE|W1_EXTINTE|W1_PARITY);
139 SCCWAIT;
140}
141#endif
142
143scc_init(chan)
144 int chan;
145{
146 register VOLATILE struct scc_reg *port;
147 register char *data;
148 register int i;
149 register Scc_channel *scc = &sccsw[chan];
150 int s;
151
152 s = splscc();
153 data = scc->scc_init;
154 port = scc->scc_port;
155 for (i = 0; i < N_INITDATA; i++) {
156 port->ctrl = *data++;
157 SCCWAIT;
158 }
159 scc_write_reg(chan, WR2, scc->scc_vec & ~0x0f);
160/* KU:XXX
161This must be bug because scc->scc_param is not initialized yet.
162 scc_set_param(chan, scc->scc_param);
163*/
164 (void) splx(s);
165}
166
167#define vec_to_scc(vec) ((((vec) - SCCVEC0) >> 3) & 0x000f)
168#define vec_to_chan(vec) scc2chan[vec_to_scc(vec)]
169
170int scc2chan[] = {
af5295ff 171 1, 0,
af5295ff
KM
172 3, 2,
173 5, 4,
174 7, 6,
175 9, 8
176};
177
af5295ff
KM
178scc_rint(vec)
179 int vec;
180{
181 int chan = vec_to_chan(vec);
182 register Scc_channel *scc = &sccsw[chan];
183 register VOLATILE struct scc_reg *port = scc->scc_port;
184 register int c;
185
186 if ((scc->scc_status & CHAN_ACTIVE) == 0) {
187 scc_reset(chan);
188 goto out;
189 }
190 if (scc->scc_status & LINE_BREAK){
191 scc->scc_status &= ~LINE_BREAK;
192 c = port->data;
193 SCCWAIT;
194 }
195 while (port->ctrl & R0_RxCA) {
196 SCCWAIT;
197 c = port->data;
198 SCCWAIT;
199#if NRS > 0
200 scc_pdma(chan, c);
201#endif
202 }
203 SCCWAIT;
204out:
205 port->ctrl = W0_RES_IUS;
206 SCCWAIT;
207}
af5295ff
KM
208
209#if NRS > 0
210scc_enable(chan)
211 int chan;
212{
213 register Scc_channel *scc = &sccsw[chan];
214 int n;
215 int s;
216
217 s = splscc();
218 if ((n = scc->r_dma.dma_count) > 0) {
219 scc->r_dma.dma_count = 0;
220 rsrint(chan, scc->r_dma.dma_addr, n);
221 } else
222 scc->scc_status |= ENABLE;
223 (void) splx(s);
224}
225
226scc_pdma(chan, c)
227 int chan;
228 int c;
229{
230 register Scc_channel *scc = &sccsw[chan];
231 int n;
232
233 if (scc->r_dma.dma_count >= SCC_BUFSIZE)
234 printf("rs%d soft fifo overflow\n", chan);
235 else
236 scc->r_dma.dma_addr[scc->r_dma.dma_count++] = c;
237 if (scc->scc_status & ENABLE || scc->r_dma.dma_count >= SCC_BUFSIZE) {
238 scc->scc_status &= ~ENABLE;
239 n = scc->r_dma.dma_count;
240 scc->r_dma.dma_count = 0;
241 rsrint(chan, scc->r_dma.dma_addr, n);
242 }
243}
244#endif /* NRS > 0 */
245
246scc_xint(vec)
247 int vec;
248{
249 int chan = vec_to_chan(vec);
250 register Scc_channel *scc = &sccsw[chan];
251 register VOLATILE struct scc_reg *port = scc->scc_port;
252
253 if (scc->scc_status & OSTOP)
254 scc->scc_status &= ~(OACTIVE|OSTOP);
255 if (scc->scc_status & OFLUSH) {
256 scc->x_dma.dma_count = 0;
257 scc->scc_status &= ~(OACTIVE|OFLUSH);
258 }
259 if ((scc->scc_status & OACTIVE) && (scc->x_dma.dma_count > 0)) {
260 port->data = *(scc->x_dma.dma_addr)++;
261 SCCWAIT;
262 scc->x_dma.dma_count--;
263 } else {
264 port->ctrl = W0_RES_TxINT;
265 SCCWAIT;
266 scc->scc_status &= ~OACTIVE;
267#if NRS > 0
268 if (scc->x_dma.dma_count == 0)
269 rsxint(chan);
270#endif
271 }
272 port->ctrl = W0_RES_IUS;
273 SCCWAIT;
274}
275
276scc_sint(vec)
277 int vec;
278{
279 int chan = vec_to_chan(vec);
280 register Scc_channel *scc = &sccsw[chan];
281 register VOLATILE struct scc_reg *port = scc->scc_port;
282 register int status;
283 register int param = 0;
284
285 port->ctrl = W0_RES_EXT;
286 SCCWAIT;
287 if ((scc->scc_status & CHAN_ACTIVE) == 0) {
288 scc_reset(chan);
289 goto out;
290 }
291 status = port->ctrl;
292 SCCWAIT;
293 if (status & R0_DCD)
294 param |= DCD;
295 if (status & R0_CTS)
296 param |= CTS;
297 if (status & R0_BREAK){
298 param |= RBREAK;
299 scc->scc_status |= LINE_BREAK;
300 }
301 if ((scc->scc_param & (DCD|CTS|RBREAK)) != param) {
302 scc->scc_param = (scc->scc_param & ~(DCD|CTS|RBREAK)) | param;
303#if NRS > 0
304 rssint(chan, scc->scc_param);
305#endif
306 }
307out:
308 port->ctrl = W0_RES_IUS;
309 SCCWAIT;
310}
311
312scc_cint(vec)
313 int vec;
314{
315 int chan = vec_to_chan(vec);
316 register Scc_channel *scc = &sccsw[chan];
317 register VOLATILE struct scc_reg *port = scc->scc_port;
318 register int status;
319 int c;
320
321 if ((scc->scc_status & CHAN_ACTIVE) == 0) {
322 scc_reset(chan);
323 goto out;
324 }
325 status = scc_read_reg(chan, RR1);
326 if (status & R1_CRC)
327 scc->scc_param |= FRAMING_ERROR;
328 if (status & R1_OVRUN) {
329 if ((scc->scc_param & OVERRUN_ERROR) == 0) {
330 scc->scc_param |= OVERRUN_ERROR;
331#if NRS > 0
332 rssint(chan, scc->scc_param);
746c97ef 333#endif
af5295ff
KM
334 }
335 }
336 if (status & R1_PARITY) {
337 scc->scc_param |= SCC_PARITY_ERROR;
338 while (port->ctrl & R0_RxCA) {
339 SCCWAIT;
340 c = port->data;
341 SCCWAIT;
342#if NRS > 0
343 if (scc->scc_param & NOCHECK)
344 scc_pdma(chan, c);
345#endif
346 }
347 SCCWAIT;
348 }
349out:
350 port->ctrl = W0_RES_ERROR;
351 SCCWAIT;
352 port->ctrl = W0_RES_IUS;
353 SCCWAIT;
354}
355
356scc_write_reg(chan, reg, data)
357 int chan, reg, data;
358{
359 register VOLATILE struct scc_reg *port = sccsw[chan].scc_port;
360
361 port->ctrl = reg;
362 SCCWAIT;
363 port->ctrl = data;
364 SCCWAIT;
365}
366
367scc_read_reg(chan, reg)
368 int chan, reg;
369{
370 register VOLATILE struct scc_reg *port = sccsw[chan].scc_port;
371 int result;
372
373 port->ctrl = reg;
374 SCCWAIT;
375 result = port->ctrl;
376 SCCWAIT;
377 return (result);
378}
379
af5295ff
KM
380#ifdef news3400
381#define DSRA 0x01
382#define RIA 0x02
383#define DSRB 0x04
384#define RIB 0x08
385
386#define DSRC 0x01
387#define RIC 0x02
388#define DSRD 0x04
389#define RID 0x08
390#define DSRE 0x10
391#define RIE 0x20
392#define DSRF 0x40
393#define RIF 0x80
394#endif /* news3400 */
395
396struct ri_dsr {
397 char *status;
398 int ri;
399 int dsr;
400} ri_dsr[] = {
af5295ff
KM
401 { (char *)SCC_STATUS0, RIA, DSRA },
402 { (char *)SCC_STATUS0, RIB, DSRB },
746c97ef 403#if !defined(news3200)
af5295ff
KM
404 { (char *)SCC_STATUS1, RIC, DSRC },
405 { (char *)SCC_STATUS1, RID, DSRD },
406 { (char *)SCC_STATUS1, RIE, DSRE },
407 { (char *)SCC_STATUS1, RIF, DSRF },
408 { (char *)SCC_STATUS2, RIC, DSRC },
409 { (char *)SCC_STATUS2, RID, DSRD },
410 { (char *)SCC_STATUS2, RIE, DSRE },
411 { (char *)SCC_STATUS2, RIF, DSRF }
746c97ef 412#endif /* !news3200 */
af5295ff
KM
413};
414
415get_ri_dsr(chan)
416 int chan;
417{
418 register struct ri_dsr *p;
419 register int status, param;
420
421 param = 0;
af5295ff
KM
422 p = &ri_dsr[chan];
423 status = *p->status;
424 if ((status & p->ri) == 0)
425 param |= RI;
426 if ((status & p->dsr) == 0)
427 param |= DSR;
af5295ff
KM
428 return (param);
429}
430
746c97ef 431#if defined(news3400)
af5295ff
KM
432/*
433 * tc0 = floor(4915200 / 32 / baudrate - 2 + 0.5);
434 */
435static int tc0[] = {
436 0, /* B0 */
437 3070, /* B50 */
438 2046, /* B75 */
439 1394, /* B110 */
440 1144, /* B134 */
441 1022, /* B150 */
442 766, /* B200 */
443 510, /* B300 */
444 254, /* B600 */
445 126, /* B1200 */
446 83, /* B1800 */
447 62, /* B2400 */
448 30, /* B4800 */
449 14, /* B9600 */
450 6, /* EXTA (B19200) */
451 2 /* EXTB (B38400) */
452 };
746c97ef 453#endif /* news3400 */
af5295ff 454
af5295ff
KM
455static int tc1[] = {
456/*
457 * tc1 = floor(3686400 / 32 / baudrate - 2 + 0.5);
458 */
459 0, /* B0 */
460 2302, /* B50 */
461 1534, /* B75 */
462 1045, /* B110 */
463 858, /* B134 */
464 766, /* B150 */
465 574, /* B200 */
466 382, /* B300 */
467 190, /* B600 */
468 94, /* B1200 */
469 62, /* B1800 */
470 46, /* B2400 */
471 22, /* B4800 */
472 10, /* B9600 */
473 4, /* B19200 */
474 1, /* B38400 */
475};
af5295ff
KM
476
477scc_set_param(chan, param)
478 int chan;
479 register int param;
480{
481 register Scc_channel *scc = &sccsw[chan];
482 register int bit, baud, *tc;
483 int s;
484
485 s = splscc();
486
487 /*
488 * Baud rate / external clock
489 */
490 if ((baud = param & BAUD_RATE) == EXTB && chan <= SCC_REMOTE1 &&
491 param & EXTCLK_ENABLE) {
492 scc_write_reg(chan, WR11, W11_RxC_RTxC|W11_TxC_TRxC);
493 bit = W4_X1;
494 } else {
af5295ff 495 tc = (chan <= SCC_REMOTE1) ? tc0 : tc1;
af5295ff
KM
496 scc_write_reg(chan, WR11, W11_RxC_BRG|W11_TxC_BRG);
497 scc_write_reg(chan, WR12, tc[baud] & 0xff);
498 scc_write_reg(chan, WR13, tc[baud] >> 8);
499 bit = W4_X16;
500 }
501
502 /*
503 * Clock mode / parity / stop bit
504 */
505 if (param & PARITY) {
506 bit |= W4_PARITY;
507 if (param & EVEN)
508 bit |= W4_EVEN;
509 }
510 switch (param & STOPBIT) {
511
512 case STOP1:
513 bit |= W4_STOP1;
514 break;
515
516 case STOP1_5:
517 bit |= W4_STOP1_5;
518 break;
519
520 case STOP2:
521 bit |= W4_STOP2;
522 break;
523
524 }
525 scc_write_reg(chan, WR4, bit);
526
527 /*
528 * Receiver enable / receive character size / auto enable
529 */
530 bit = (param & RXE ? W3_RxE : 0);
531 switch (param & CHAR_SIZE) {
532
533 case C5BIT:
534 break;
535
536 case C6BIT:
537 bit |= W3_Rx6BIT;
538 break;
539
540 case C7BIT:
541 bit |= W3_Rx7BIT;
542 break;
543
544 case C8BIT:
545 bit |= W3_Rx8BIT;
546 break;
547 }
548#ifdef AUTO_ENABLE
549 if (param & AUTO_ENABLE)
550 bit |= W3_AUTO;
551#endif /* AUTO_ENABLE */
552 scc_write_reg(chan, WR3, bit);
553
554 /*
555 * Transmitter enable / transmit character size / RTS / DTR / BREAK
556 */
557 bit = (param & TXE ? W5_TxE : 0);
558 switch (param & CHAR_SIZE) {
559
560 case C5BIT:
561 break;
562
563 case C6BIT:
564 bit |= W5_Tx6BIT;
565 break;
566
567 case C7BIT:
568 bit |= W5_Tx7BIT;
569 break;
570
571 case C8BIT:
572 bit |= W5_Tx8BIT;
573 break;
574 }
575 if (param & RTS)
576 bit |= W5_RTS;
577 if (param & DTR)
578 bit |= W5_DTR;
579 if (param & XBREAK)
580 bit |= W5_BREAK;
581 scc_write_reg(chan, WR5, bit);
582 scc->scc_param = param;
583 (void) splx(s);
584 return (0);
585}
586
587scc_get_param(chan)
588 int chan;
589{
590 register Scc_channel *scc = &sccsw[chan];
591
592 scc->scc_param = (scc->scc_param & ~(RI|DSR)) | get_ri_dsr(chan);
593 return (scc->scc_param);
594}
595
596scc_get_status(chan)
597 int chan;
598{
599
600 return (sccsw[chan].scc_status);
601}
602
603scc_set_status(chan, stat)
604 int chan, stat;
605{
606
607 sccsw[chan].scc_status = stat;
608
609 return (0);
610}
611
612scc_flush(chan)
613 int chan;
614{
615 register Scc_channel *scc = &sccsw[chan];
616
617 if (scc->scc_status & OACTIVE)
618 scc->scc_status |= OFLUSH;
619 else if (scc->x_dma.dma_count > 0) {
620 scc->x_dma.dma_count = 0;
621#if NRS > 0
622 rsxint(chan);
623#endif
624 }
625 return (0);
626}
627
628scc_start(chan)
629 int chan;
630{
631 register Scc_channel *scc = &sccsw[chan];
632
633 if ((scc->scc_status & OACTIVE) == 0 && scc->x_dma.dma_count > 0) {
634 scc->scc_port->data = *(scc->x_dma.dma_addr)++;
635 SCCWAIT;
636 scc->x_dma.dma_count--;
637 scc->scc_status |= OACTIVE;
638 }
639 return (0);
640}
641
642scc_stop(chan)
643 int chan;
644{
645 register Scc_channel *scc = &sccsw[chan];
646
647 if (scc->scc_status & OACTIVE)
648 scc->scc_status |= OSTOP;
649 return (0);
650}
651
652scc_write(chan, buf, count)
653 int chan;
654 caddr_t buf;
655 int count;
656{
657 register Scc_channel *scc = &sccsw[chan];
658
659 if (count <= 0)
660 return (0);
661 scc->x_dma.dma_addr = buf;
662 scc->x_dma.dma_count = count;
663 scc_start(chan);
664 return (count);
665}
666
667scc_error_write(chan, buf, count)
668 int chan;
669 register char *buf;
670 register int count;
671{
672 register int i;
673
674 for (i = 0; i < count; i++)
675 scc_putc(chan, *buf++);
676 return (i);
677}
678
679scc_reset(chan)
680 int chan;
681{
682 register Scc_channel *scc = &sccsw[chan];
683
684 while (scc_getc(chan) != -1)
685 ;
686 scc->scc_status &= ~CHAN_ACTIVE;
687}