zs.c revision 1.2 1 i* $NetBSD: zs.c,v 1.2 1996/03/17 01:35:05 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 1993 Paul Mackerras.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software withough specific prior written permission
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 /*
30 * Serial I/O via an SCC,
31 */
32 #include <sys/param.h>
33 #include <sys/conf.h>
34 #include <sys/ioctl.h>
35 #include <sys/proc.h>
36 #include <sys/user.h>
37 #include <sys/tty.h>
38 #include <sys/uio.h>
39 #include <sys/callout.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
42 #include <sys/syslog.h>
43 #include <sys/fcntl.h>
44 #include <sys/device.h>
45 #include <machine/cpu.h>
46 #include <dev/cons.h>
47 #include <mvme68k/dev/iio.h>
48 #include <mvme68k/dev/scc.h>
49 #include <mvme68k/dev/pccreg.h>
50
51 #include "zs.h"
52 #if NZS > 0
53
54 /*#define PCLK_FREQ 8333333*/
55 #undef PCLK_FREQ /* XXXCDC */
56 #define PCLK_FREQ 5000000
57 #define NZSLINE (NZS*2)
58
59 #define RECV_BUF 512
60 #define ERROR_DET 0xed
61
62 #define TS_DRAIN TS_FLUSH/* waiting for output to drain */
63
64 #define splzs() spl4()
65
66 struct zs {
67 short flags; /* see below */
68 char rr0; /* holds previous CTS, DCD state */
69 unsigned char imask; /* mask for input chars */
70 int nzs_open; /* # opens as /dev/zsn */
71 int nkbd_open; /* # opens as a keyboard */
72 int gsp_unit; /* unit to send kbd chars to */
73 struct tty *tty; /* link to tty structure */
74 struct sccregs scc; /* SCC shadow registers */
75 u_char *rcv_get;
76 u_char *rcv_put;
77 u_char *rcv_end;
78 volatile int rcv_count;
79 int rcv_len;
80 char *send_ptr;
81 int send_count;
82 int sent_count;
83 volatile char modem_state;
84 volatile char modem_change;
85 volatile short hflags;
86 char rcv_buf[RECV_BUF];
87 };
88
89 /* Bits in flags */
90 #define ZS_SIDEA 1
91 #define ZS_INITED 2
92 #define ZS_INTEN 4
93 #define ZS_RESET 8
94 #define ZS_CONSOLE 0x20
95
96 /* Bits in hflags */
97 #define ZH_OBLOCK 1 /* output blocked by CTS */
98 #define ZH_SIRQ 2 /* soft interrupt request */
99 #define ZH_TXING 4 /* transmitter active */
100 #define ZH_RXOVF 8 /* receiver buffer overflow */
101
102 struct zssoftc {
103 struct device dev;
104 struct zs zs[2];
105 };
106
107 struct tty *zs_tty[NZSLINE];
108
109 struct termios zs_cons_termios;
110 int zs_cons_unit = 0;
111 int zs_is_console = 0;
112 struct sccregs *zs_cons_scc;
113
114 int zsopen __P((dev_t, int, int, struct proc *));
115 void zsstart __P((struct tty *));
116 int zsparam __P((struct tty *, struct termios *));
117 int zsirq __P((int unit));
118 void zs_softint __P((void));
119
120 unsigned long sir_zs;
121 void zs_softint();
122
123 #define zsunit(dev) (minor(dev) >> 1)
124 #define zsside(dev) (minor(dev) & 1)
125
126 /*
127 * Autoconfiguration stuff.
128 */
129 void zsattach __P((struct device *, struct device *, void *));
130 int zsmatch __P((struct device *, void *, void *));
131
132 struct cfattach zs_ca = {
133 sizeof(struct zssoftc), zsmatch, zsattach
134 };
135
136 struct cfdriver zs_cd = {
137 NULL, "zs", DV_TTY, 0
138 };
139
140 int
141 zsmatch(parent, vcf, args)
142 struct device *parent;
143 void *vcf, *args;
144 {
145 struct cfdata *cf = vcf;
146
147 return !badbaddr((caddr_t) IIO_CFLOC_ADDR(cf));
148 }
149
150 void
151 zsattach(parent, self, args)
152 struct device *parent, *self;
153 void *args;
154 {
155 struct zssoftc *dv;
156 struct zs *zp, *zc;
157 u_char ir;
158 volatile struct scc *scc;
159 int zs_level = IIO_CFLOC_LEVEL(self->dv_cfdata);
160
161 iio_print(self->dv_cfdata);
162
163 /* connect the interrupt */
164 dv = (struct zssoftc *) self;
165 pccintr_establish(PCCV_ZS, zsirq, zs_level, self->dv_unit);
166 /* XXXCDC: needs some work to handle zs1 */
167
168 zp = &dv->zs[0];
169 scc = (volatile struct scc *) IIO_CFLOC_ADDR(self->dv_cfdata);
170
171 if (zs_is_console && self->dv_unit == zsunit(zs_cons_unit)) {
172 /* SCC is the console - it's already reset */
173 zc = zp + zsside(zs_cons_unit);
174 zc->scc = *zs_cons_scc;
175 zs_cons_scc = &zc->scc;
176 zc->flags |= ZS_CONSOLE;
177 } else {
178 /* reset the SCC */
179 scc->cr = 0;
180 scc->cr = 9;
181 scc->cr = 0xC0; /* hardware reset of SCC, both sides */
182 }
183
184 /* side A */
185 zp->scc.s_adr = scc + 1;
186 zp->flags |= ZS_SIDEA | ZS_RESET;
187
188 /* side B */
189 ++zp;
190 zp->scc.s_adr = scc;
191 zp->flags |= ZS_RESET;
192
193 if (sir_zs == 0)
194 sir_zs = allocate_sir(zs_softint, 0);
195 printf("\n");
196
197 ir = sys_pcc->zs_int;
198 if ((ir & PCC_IMASK) != 0 && (ir & PCC_IMASK) != zs_level)
199 panic("zs configured at different IPLs");
200 sys_pcc->zs_int = zs_level | PCC_IENABLE | PCC_ZSEXTERN;
201 }
202
203 zs_ttydef(struct zs *zp)
204 {
205 struct tty *tp = zp->tty;
206
207 if ((zp->flags & ZS_CONSOLE) == 0) {
208 tp->t_iflag = TTYDEF_IFLAG;
209 tp->t_oflag = TTYDEF_OFLAG;
210 tp->t_cflag = TTYDEF_CFLAG;
211 tp->t_lflag = TTYDEF_LFLAG;
212 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
213 } else
214 tp->t_termios = zs_cons_termios;
215 ttychars(tp);
216 ttsetwater(tp);
217 tp->t_oproc = zsstart;
218 tp->t_param = zsparam;
219
220 zp->rcv_get = zp->rcv_buf;
221 zp->rcv_put = zp->rcv_buf;
222 zp->rcv_end = zp->rcv_buf + sizeof(zp->rcv_buf);
223 zp->rcv_len = sizeof(zp->rcv_buf) / 2;
224 }
225
226 struct tty *
227 zstty(dev)
228 dev_t dev;
229 {
230
231 if (minor(dev) < NZSLINE)
232 return (zs_tty[minor(dev)]);
233
234 return (NULL);
235 }
236
237 /* ARGSUSED */
238 zsopen(dev_t dev, int flag, int mode, struct proc * p)
239 {
240 register struct tty *tp;
241 int error;
242 struct zs *zp;
243 struct zssoftc *dv;
244
245 if (zsunit(dev) > zs_cd.cd_ndevs
246 || (dv = (struct zssoftc *) zs_cd.cd_devs[zsunit(dev)]) == NULL)
247 return ENODEV;
248
249 zp = &dv->zs[zsside(dev)];
250 if (zp->tty == NULL) {
251 zp->tty = ttymalloc();
252 zs_ttydef(zp);
253 if (minor(dev) < NZSLINE)
254 zs_tty[minor(dev)] = zp->tty;
255 }
256 tp = zp->tty;
257 tp->t_dev = dev;
258
259 if ((tp->t_state & TS_ISOPEN) == 0) {
260 tp->t_state |= TS_WOPEN;
261 zs_init(zp);
262 if ((zp->modem_state & SCC_DCD) != 0)
263 tp->t_state |= TS_CARR_ON;
264 } else
265 if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0)
266 return (EBUSY);
267
268 error = ((*linesw[tp->t_line].l_open) (dev, tp));
269
270 if (error == 0)
271 ++zp->nzs_open;
272 return error;
273 }
274
275 int
276 zsclose(dev, flag, mode, p)
277 dev_t dev;
278 int flag, mode;
279 struct proc *p;
280 {
281 struct zs *zp;
282 struct tty *tp;
283 struct zssoftc *dv;
284 int s;
285
286 if (zsunit(dev) > zs_cd.cd_ndevs
287 || (dv = (struct zssoftc *) zs_cd.cd_devs[zsunit(dev)]) == NULL)
288 return ENODEV;
289 zp = &dv->zs[zsside(dev)];
290 tp = zp->tty;
291
292 if (zp->nkbd_open == 0) {
293 (*linesw[tp->t_line].l_close) (tp, flag);
294 s = splzs();
295 if ((zp->flags & ZS_CONSOLE) == 0 && (tp->t_cflag & HUPCL) != 0)
296 ZBIC(&zp->scc, 5, 0x82); /* drop DTR, RTS */
297 ZBIC(&zp->scc, 3, 1); /* disable receiver */
298 splx(s);
299 ttyclose(tp);
300 }
301 zp->nzs_open = 0;
302 return (0);
303 }
304
305 /*ARGSUSED*/
306 zsread(dev, uio, flag)
307 dev_t dev;
308 struct uio *uio;
309 int flag;
310 {
311 struct zssoftc *dv = (struct zssoftc *) zs_cd.cd_devs[zsunit(dev)];
312 struct zs *zp = &dv->zs[zsside(dev)];
313 struct tty *tp = zp->tty;
314
315 return ((*linesw[tp->t_line].l_read) (tp, uio, flag));
316 }
317
318 /*ARGSUSED*/
319 zswrite(dev, uio, flag)
320 dev_t dev;
321 struct uio *uio;
322 int flag;
323 {
324 struct zssoftc *dv = (struct zssoftc *) zs_cd.cd_devs[zsunit(dev)];
325 struct zs *zp = &dv->zs[zsside(dev)];
326 struct tty *tp = zp->tty;
327
328 return ((*linesw[tp->t_line].l_write) (tp, uio, flag));
329 }
330
331 zsioctl(dev, cmd, data, flag, p)
332 dev_t dev;
333 caddr_t data;
334 int cmd, flag;
335 struct proc *p;
336 {
337 struct zssoftc *dv = (struct zssoftc *) zs_cd.cd_devs[zsunit(dev)];
338 struct zs *zp = &dv->zs[zsside(dev)];
339 struct tty *tp = zp->tty;
340 register struct sccregs *scc = &zp->scc;
341 register int error, s;
342
343 error = (*linesw[tp->t_line].l_ioctl) (tp, cmd, data, flag, p);
344 if (error >= 0)
345 return (error);
346 error = ttioctl(tp, cmd, data, flag, p);
347 if (error >= 0)
348 return (error);
349 error = 0;
350 s = splzs();
351 switch (cmd) {
352 case TIOCSDTR:
353 ZBIS(scc, 5, 0x80);
354 break;
355 case TIOCCDTR:
356 ZBIC(scc, 5, 0x80);
357 break;
358 case TIOCSBRK:
359 splx(s);
360 zs_drain(zp);
361 s = splzs();
362 ZBIS(scc, 5, 0x10);
363 spltty();
364 zs_unblock(tp);
365 break;
366 case TIOCCBRK:
367 ZBIC(scc, 5, 0x10);
368 break;
369 case TIOCMGET:
370 *(int *) data = zscc_mget(scc);
371 break;
372 case TIOCMSET:
373 zscc_mset(scc, *(int *) data);
374 zscc_mclr(scc, ~*(int *) data);
375 break;
376 case TIOCMBIS:
377 zscc_mset(scc, *(int *) data);
378 break;
379 case TIOCMBIC:
380 zscc_mclr(scc, *(int *) data);
381 break;
382 default:
383 error = ENOTTY;
384 }
385 splx(s);
386 return error;
387 }
388
389 zsparam(tp, t)
390 struct tty *tp;
391 struct termios *t;
392 {
393 struct zssoftc *dv = (struct zssoftc *) zs_cd.cd_devs[zsunit(tp->t_dev)];
394 struct zs *zp = &dv->zs[zsside(tp->t_dev)];
395 register int s;
396
397 zs_drain(zp);
398 s = splzs();
399 zp->imask = zscc_params(&zp->scc, t);
400 tp->t_ispeed = t->c_ispeed;
401 tp->t_ospeed = t->c_ospeed;
402 tp->t_cflag = t->c_cflag;
403 if ((tp->t_cflag & CCTS_OFLOW) == 0)
404 zp->hflags &= ~ZH_OBLOCK;
405 else
406 if ((zp->modem_state & 0x20) == 0)
407 zp->hflags |= ZH_OBLOCK;
408 spltty();
409 zs_unblock(tp);
410 splx(s);
411 return 0;
412 }
413
414 void
415 zsstart(tp)
416 struct tty *tp;
417 {
418 struct zssoftc *dv = (struct zssoftc *) zs_cd.cd_devs[zsunit(tp->t_dev)];
419 struct zs *zp = &dv->zs[zsside(tp->t_dev)];
420 register int s, n;
421
422 s = spltty();
423 if ((tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP | TS_DRAIN)) == 0) {
424 n = ndqb(&tp->t_outq, 0);
425 if (n > 0) {
426 tp->t_state |= TS_BUSY;
427 splzs();
428 zp->hflags |= ZH_TXING;
429 zp->send_ptr = tp->t_outq.c_cf;
430 zp->send_count = n;
431 zp->sent_count = 0;
432 zs_txint(zp);
433 spltty();
434 }
435 }
436 splx(s);
437 }
438
439 zsstop(struct tty * tp, int flag)
440 {
441 struct zssoftc *dv = (struct zssoftc *) zs_cd.cd_devs[zsunit(tp->t_dev)];
442 struct zs *zp = &dv->zs[zsside(tp->t_dev)];
443 int s, n;
444
445 s = splzs();
446 zp->send_count = 0;
447 n = zp->sent_count;
448 zp->sent_count = 0;
449 if ((tp->t_state & TS_BUSY) != 0 && (flag & FWRITE) == 0) {
450 tp->t_state &= ~TS_BUSY;
451 spltty();
452 ndflush(&tp->t_outq, n);
453 if (tp->t_outq.c_cc <= tp->t_lowat) {
454 if (tp->t_state & TS_ASLEEP) {
455 tp->t_state &= ~TS_ASLEEP;
456 wakeup((caddr_t) & tp->t_outq);
457 }
458 selwakeup(&tp->t_wsel);
459 }
460 }
461 splx(s);
462 }
463
464 zs_init(zp)
465 struct zs *zp;
466 {
467 register int s;
468
469 s = splzs();
470 zscc_init(zp, &zp->tty->t_termios);
471 zp->rr0 = zp->modem_state = ZREAD0(&zp->scc);
472 ZBIS(&zp->scc, 1, 0x13);/* ints on tx, rx and ext/status */
473 ZBIS(&zp->scc, 9, 8); /* enable ints */
474 zp->flags |= ZS_INTEN;
475 splx(s);
476 }
477
478 zscc_init(zp, par)
479 struct zs *zp;
480 struct termios *par;
481 {
482 struct sccregs *scc;
483
484 scc = &zp->scc;
485 ZWRITE(scc, 2, 0);
486 ZWRITE(scc, 10, 0);
487 ZWRITE(scc, 11, 0x50); /* rx & tx clock = brgen */
488 ZWRITE(scc, 14, 3); /* brgen enabled, from pclk */
489 zp->imask = zscc_params(scc, par);
490 ZBIS(scc, 5, 0x82); /* set DTR and RTS */
491 zp->flags |= ZS_INITED;
492 }
493
494 int
495 zscc_params(scc, par)
496 struct sccregs *scc;
497 struct termios *par;
498 {
499 unsigned divisor, speed;
500 int spd, imask, ints;
501
502 speed = par->c_ospeed;
503 if (speed == 0) {
504 /* disconnect - drop DTR & RTS, disable receiver */
505 ZBIC(scc, 5, 0x82);
506 ZBIC(scc, 3, 1);
507 return 0xFF;
508 }
509 if ((par->c_cflag & CREAD) == 0)
510 ZBIC(scc, 3, 1);/* disable receiver */
511 divisor = (PCLK_FREQ / 32 + (speed >> 1)) / speed - 2;
512 ZWRITE(scc, 12, divisor);
513 ZWRITE(scc, 13, divisor >> 8);
514 switch (par->c_cflag & CSIZE) {
515 case CS5:
516 spd = 0;
517 imask = 0x1F;
518 break;
519 case CS6:
520 spd = 0x40;
521 imask = 0x3F;
522 break;
523 case CS7:
524 spd = 0x20;
525 imask = 0x7F;
526 break;
527 default:
528 spd = 0x60;
529 imask = 0xFF;
530 }
531 ZWRITE(scc, 5, (scc->s_val[5] & ~0x60) | spd);
532 ZWRITE(scc, 3, (scc->s_val[3] & ~0xC0) | (spd << 1));
533 spd = par->c_cflag & CSTOPB ? 8 : 0;
534 spd |= par->c_cflag & PARENB ? par->c_cflag & PARODD ? 1 : 3 : 0;
535 ZWRITE(scc, 4, 0x44 | spd);
536 ZBIS(scc, 5, 8); /* enable transmitter */
537 if ((par->c_cflag & CREAD) != 0)
538 ZBIS(scc, 3, 1);/* enable receiver */
539 ints = 0;
540 if ((par->c_cflag & CLOCAL) == 0)
541 ints |= SCC_DCD;
542 if ((par->c_cflag & CCTS_OFLOW) != 0)
543 ints |= SCC_CTS;
544 ZWRITE(scc, 15, ints);
545 return imask;
546 }
547
548 zscc_mget(register struct sccregs * scc)
549 {
550 int bits = 0, rr0;
551
552 if ((scc->s_val[3] & SCC_RCVEN) != 0)
553 bits |= TIOCM_LE;
554 if ((scc->s_val[5] & SCC_DTR) != 0)
555 bits |= TIOCM_DTR;
556 if ((scc->s_val[5] & SCC_RTS) != 0)
557 bits |= TIOCM_RTS;
558 rr0 = ZREAD0(scc);
559 if ((rr0 & SCC_CTS) != 0)
560 bits |= TIOCM_CTS;
561 if ((rr0 & SCC_DCD) != 0)
562 bits |= TIOCM_CAR;
563 return bits;
564 }
565
566 zscc_mset(register struct sccregs * scc, int bits)
567 {
568 if ((bits & TIOCM_LE) != 0)
569 ZBIS(scc, 3, SCC_RCVEN);
570 if ((bits & TIOCM_DTR) != 0)
571 ZBIS(scc, 5, SCC_DTR);
572 if ((bits & TIOCM_RTS) != 0)
573 ZBIS(scc, 5, SCC_RTS);
574 }
575
576 zscc_mclr(register struct sccregs * scc, int bits)
577 {
578 if ((bits & TIOCM_LE) != 0)
579 ZBIC(scc, 3, SCC_RCVEN);
580 if ((bits & TIOCM_DTR) != 0)
581 ZBIC(scc, 5, TIOCM_DTR);
582 if ((bits & TIOCM_RTS) != 0)
583 ZBIC(scc, 5, SCC_RTS);
584 }
585
586 zs_drain(register struct zs * zp)
587 {
588 register int s;
589
590 zp->tty->t_state |= TS_DRAIN;
591 /* wait for Tx buffer empty and All sent bits to be set */
592 s = splzs();
593 while ((ZREAD0(&zp->scc) & SCC_TXRDY) == 0
594 || (ZREAD(&zp->scc, 1) & 1) == 0) {
595 splx(s);
596 DELAY(100);
597 s = splzs();
598 }
599 splx(s);
600 }
601
602 zs_unblock(register struct tty * tp)
603 {
604 tp->t_state &= ~TS_DRAIN;
605 if (tp->t_outq.c_cc != 0)
606 zsstart(tp);
607 }
608
609 /*
610 * Hardware interrupt from an SCC.
611 */
612 int
613 zsirq(int unit)
614 {
615 struct zssoftc *dv = (struct zssoftc *) zs_cd.cd_devs[unit];
616 register struct zs *zp = &dv->zs[0];
617 register int ipend, x;
618 register volatile struct scc *scc;
619
620 x = splzs();
621 scc = zp->scc.s_adr;
622 scc->cr = 3; /* read int pending from A side */
623 DELAY(5);
624 ipend = scc->cr;
625 if ((ipend & 0x20) != 0)
626 zs_rxint(zp);
627 if ((ipend & 0x10) != 0)
628 zs_txint(zp);
629 if ((ipend & 0x8) != 0)
630 zs_extint(zp);
631 ++zp; /* now look for B side ints */
632 if ((ipend & 0x4) != 0)
633 zs_rxint(zp);
634 if ((ipend & 0x2) != 0)
635 zs_txint(zp);
636 if ((ipend & 0x1) != 0)
637 zs_extint(zp);
638 splx(x);
639 return ipend != 0;
640 }
641
642 zs_txint(register struct zs * zp)
643 {
644 struct tty *tp = zp->tty;
645 struct sccregs *scc;
646 int c;
647 u_char *get;
648
649 scc = &zp->scc;
650 ZWRITE0(scc, 0x28); /* reset Tx interrupt */
651 if ((zp->hflags & ZH_OBLOCK) == 0) {
652 get = zp->send_ptr;
653 while ((ZREAD0(scc) & SCC_TXRDY) != 0 && zp->send_count > 0) {
654 c = *get++;
655 ZWRITED(scc, c);
656 --zp->send_count;
657 ++zp->sent_count;
658 }
659 zp->send_ptr = get;
660 if (zp->send_count == 0 && (zp->hflags & ZH_TXING) != 0) {
661 zp->hflags &= ~ZH_TXING;
662 zp->hflags |= ZH_SIRQ;
663 setsoftint(sir_zs);
664 }
665 }
666 }
667
668 zs_rxint(register struct zs * zp)
669 {
670 register int stat, c, n, extra;
671 u_char *put;
672
673 put = zp->rcv_put;
674 n = zp->rcv_count;
675 for (;;) {
676 if ((ZREAD0(&zp->scc) & SCC_RXFULL) == 0) /* check Rx full */
677 break;
678 stat = ZREAD(&zp->scc, 1) & 0x70;
679 c = ZREADD(&zp->scc) & zp->imask;
680 /* stat encodes parity, overrun, framing errors */
681 if (stat != 0)
682 ZWRITE0(&zp->scc, 0x30); /* reset error */
683 if ((zp->hflags & ZH_RXOVF) != 0) {
684 zp->hflags &= ~ZH_RXOVF;
685 stat |= 0x20;
686 }
687 extra = (stat != 0 || c == ERROR_DET) ? 2 : 0;
688 if (n + extra + 1 < zp->rcv_len) {
689 if (extra != 0) {
690 *put++ = ERROR_DET;
691 if (put >= zp->rcv_end)
692 put = zp->rcv_buf;
693 *put++ = stat;
694 if (put >= zp->rcv_end)
695 put = zp->rcv_buf;
696 n += 2;
697 }
698 *put++ = c;
699 if (put >= zp->rcv_end)
700 put = zp->rcv_buf;
701 ++n;
702 } else
703 zp->hflags |= ZH_RXOVF;
704 }
705 if (n > zp->rcv_count) {
706 zp->rcv_put = put;
707 zp->rcv_count = n;
708 zp->hflags |= ZH_SIRQ;
709 setsoftint(sir_zs);
710 }
711 }
712
713 /* Ext/status interrupt */
714 zs_extint(register struct zs * zp)
715 {
716 int rr0;
717 struct tty *tp = zp->tty;
718
719 rr0 = ZREAD0(&zp->scc);
720 ZWRITE0(&zp->scc, 0x10);/* reset ext/status int */
721 if ((tp->t_cflag & CCTS_OFLOW) != 0) {
722 if ((rr0 & 0x20) == 0)
723 zp->hflags |= ZH_OBLOCK;
724 else {
725 zp->hflags &= ~ZH_OBLOCK;
726 if ((rr0 & SCC_TXRDY) != 0)
727 zs_txint(zp);
728 }
729 }
730 zp->modem_change |= rr0 ^ zp->modem_state;
731 zp->modem_state = rr0;
732 zp->hflags |= ZH_SIRQ;
733 setsoftint(sir_zs);
734 }
735
736 void
737 zs_softint()
738 {
739 int s, n, n0, c, stat, rr0;
740 struct zs *zp;
741 struct tty *tp;
742 u_char *get;
743 int unit, side;
744
745 s = splzs();
746 for (unit = 0; unit < zs_cd.cd_ndevs; ++unit) {
747 if (zs_cd.cd_devs[unit] == NULL)
748 continue;
749 zp = &((struct zssoftc *) zs_cd.cd_devs[unit])->zs[0];
750 for (side = 0; side < 2; ++side, ++zp) {
751 if ((zp->hflags & ZH_SIRQ) == 0)
752 continue;
753 zp->hflags &= ~ZH_SIRQ;
754 tp = zp->tty;
755
756 /* check for tx done */
757 spltty();
758 if (tp != NULL && zp->send_count == 0
759 && (tp->t_state & TS_BUSY) != 0) {
760 tp->t_state &= ~(TS_BUSY | TS_FLUSH);
761 ndflush(&tp->t_outq, zp->sent_count);
762 if (tp->t_outq.c_cc <= tp->t_lowat) {
763 if (tp->t_state & TS_ASLEEP) {
764 tp->t_state &= ~TS_ASLEEP;
765 wakeup((caddr_t) & tp->t_outq);
766 }
767 selwakeup(&tp->t_wsel);
768 }
769 if (tp->t_line != 0)
770 (*linesw[tp->t_line].l_start) (tp);
771 else
772 zsstart(tp);
773 }
774 splzs();
775
776 /* check for received characters */
777 get = zp->rcv_get;
778 while (zp->rcv_count > 0) {
779 c = *get++;
780 if (get >= zp->rcv_end)
781 get = zp->rcv_buf;
782 if (c == ERROR_DET) {
783 stat = *get++;
784 if (get >= zp->rcv_end)
785 get = zp->rcv_buf;
786 c = *get++;
787 if (get >= zp->rcv_end)
788 get = zp->rcv_buf;
789 zp->rcv_count -= 3;
790 } else {
791 stat = 0;
792 --zp->rcv_count;
793 }
794 spltty();
795 if (tp == NULL || (tp->t_state & TS_ISOPEN) == 0)
796 continue;
797 if (zp->nzs_open == 0) {
798 #ifdef notdef
799 if (stat == 0)
800 kbd_newchar(zp->gsp_unit, c);
801 #endif
802 } else {
803 if ((stat & 0x10) != 0)
804 c |= TTY_PE;
805 if ((stat & 0x20) != 0) {
806 log(LOG_WARNING, "zs: fifo overflow\n");
807 c |= TTY_FE; /* need some error for
808 * slip stuff */
809 }
810 if ((stat & 0x40) != 0)
811 c |= TTY_FE;
812 (*linesw[tp->t_line].l_rint) (c, tp);
813 }
814 splzs();
815 }
816 zp->rcv_get = get;
817
818 /* check for modem lines changing */
819 while (zp->modem_change != 0 || zp->modem_state != zp->rr0) {
820 rr0 = zp->rr0 ^ zp->modem_change;
821 zp->modem_change = rr0 ^ zp->modem_state;
822
823 /* Check if DCD (carrier detect) has changed */
824 if (tp != NULL && (rr0 & 8) != (zp->rr0 & 8)) {
825 spltty();
826 ttymodem(tp, rr0 & 8);
827 /* XXX possibly should disable line if
828 * return value is 0 */
829 splzs();
830 }
831 zp->rr0 = rr0;
832 }
833 }
834 }
835 splx(s);
836 }
837
838 /*
839 * Routines to divert an SCC channel to the input side of /dev/gsp
840 * for the keyboard.
841 */
842 int
843 zs_kbdopen(int unit, int gsp_unit, struct termios * tiop, struct proc * p)
844 {
845 struct zssoftc *dv = (struct zssoftc *) zs_cd.cd_devs[zsunit(unit)];
846 struct zs *zp = &dv->zs[zsside(unit)];
847 int error;
848
849 error = zsopen(unit, 0, 0, p);
850 if (error != 0)
851 return error;
852 ++zp->nkbd_open;
853 --zp->nzs_open;
854 zsparam(zp->tty, tiop);
855 zp->gsp_unit = gsp_unit;
856 return 0;
857 }
858
859 void
860 zs_kbdclose(int unit)
861 {
862 struct zssoftc *dv = (struct zssoftc *) zs_cd.cd_devs[zsunit(unit)];
863 struct zs *zp = &dv->zs[zsside(unit)];
864
865 zp->nkbd_open = 0;
866 if (zp->nzs_open == 0)
867 zsclose(unit, 0, 0, 0);
868 }
869
870 void
871 zs_kbdput(int unit, int c)
872 {
873 struct zssoftc *dv = (struct zssoftc *) zs_cd.cd_devs[zsunit(unit)];
874 struct zs *zp = &dv->zs[zsside(unit)];
875 struct tty *tp = zp->tty;
876
877 putc(c, &tp->t_outq);
878 zsstart(tp);
879 }
880
881 /*
882 * Routines for using side A of the first SCC as a console.
883 */
884
885 /* probe for the SCC; should check hardware */
886 zscnprobe(cp)
887 struct consdev *cp;
888 {
889 int maj;
890 char *prom_cons;
891 extern char *prom_getvar();
892
893 /* locate the major number */
894 for (maj = 0; maj < nchrdev; maj++)
895 if (cdevsw[maj].d_open == zsopen)
896 break;
897
898 /* initialize required fields */
899 cp->cn_dev = makedev(maj, 0);
900 cp->cn_pri = CN_NORMAL;
901
902 return 1;
903 }
904
905 /* initialize the keyboard for use as the console */
906 struct termios zscn_termios = {
907 TTYDEF_IFLAG,
908 TTYDEF_OFLAG,
909 TTYDEF_CFLAG,
910 TTYDEF_LFLAG,
911 {0},
912 TTYDEF_SPEED,
913 TTYDEF_SPEED
914 };
915
916 struct sccregs zs_cons_sccregs;
917 int zs_cons_imask;
918
919 unsigned zs_cons_addrs[] = {ZS0_PHYS, ZS1_PHYS};
920
921
922 zscninit()
923 {
924 zs_cnsetup(0, &zscn_termios);
925 }
926
927 /* Polling routine for console input from a serial port. */
928 int
929 zscngetc(dev_t dev)
930 {
931 register struct sccregs *scc = zs_cons_scc;
932 int c, s, stat;
933
934 s = splzs();
935 for (;;) {
936 while ((ZREAD0(scc) & SCC_RXFULL) == 0) /* wait for Rx full */
937 ;
938 stat = ZREAD(scc, 1) & 0x70;
939 c = ZREADD(scc) & zs_cons_imask;
940 /* stat encodes parity, overrun, framing errors */
941 if (stat == 0)
942 break;
943 ZWRITE0(scc, 0x30); /* reset error */
944 }
945 splx(s);
946 return c;
947 }
948
949 zscnputc(dev_t dev, int c)
950 {
951 register struct sccregs *scc = zs_cons_scc;
952 int s;
953
954 s = splzs();
955 while ((ZREAD0(scc) & SCC_TXRDY) == 0);
956 ZWRITED(scc, c);
957 splx(s);
958 }
959
960 zs_cnsetup(int unit, struct termios * tiop)
961 {
962 register volatile struct scc *scc_adr;
963 register struct sccregs *scc;
964
965 zs_cons_unit = unit;
966 zs_is_console = 1;
967 zs_cons_scc = scc = &zs_cons_sccregs;
968
969 scc_adr = (volatile struct scc *) IIOV(zs_cons_addrs[zsunit(unit)]);
970
971 scc_adr[1].cr = 0;
972 scc_adr[1].cr = 9;
973 scc_adr[1].cr = 0xC0; /* hardware reset of SCC, both sides */
974 if (!zsside(unit))
975 ++scc_adr;
976
977 scc->s_adr = scc_adr;
978 ZWRITE(scc, 2, 0);
979 ZWRITE(scc, 10, 0);
980 ZWRITE(scc, 11, 0x50); /* rx & tx clock = brgen */
981 ZWRITE(scc, 14, 3); /* brgen enabled, from pclk */
982 zs_cons_imask = zscc_params(scc, tiop);
983 ZBIS(scc, 5, 0x82); /* set DTR and RTS */
984
985 zs_cons_termios = *tiop;/* save for later */
986 }
987
988 /*
989 * Routines for using the keyboard SCC as the input side of
990 * the 'gsp' console device.
991 */
992
993 /* probe for the keyboard; should check hardware */
994 zs_kbdcnprobe(cp, unit)
995 struct consdev *cp;
996 int unit;
997 {
998 return (unsigned) unit < NZSLINE;
999 }
1000 #endif /* NZS */
1001