ser.c revision 1.49 1 /* $NetBSD: ser.c,v 1.49 1998/07/22 19:13:02 is Exp $ */
2
3 /*
4 * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
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. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * @(#)ser.c 7.12 (Berkeley) 6/27/91
36 */
37 /*
38 * XXX This file needs major cleanup it will never service more than one
39 * XXX unit.
40 */
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/ioctl.h>
45 #include <sys/device.h>
46 #include <sys/tty.h>
47 #include <sys/proc.h>
48 #include <sys/file.h>
49 #include <sys/malloc.h>
50 #include <sys/uio.h>
51 #include <sys/kernel.h>
52 #include <sys/syslog.h>
53 #include <sys/queue.h>
54 #include <machine/cpu.h>
55 #include <amiga/amiga/device.h>
56 #include <amiga/dev/serreg.h>
57 #include <amiga/amiga/custom.h>
58 #include <amiga/amiga/cia.h>
59 #include <amiga/amiga/cc.h>
60
61 #include <dev/cons.h>
62
63 #include <sys/conf.h>
64 #include <machine/conf.h>
65
66 #include "ser.h"
67 #if NSER > 0
68
69 void serattach __P((struct device *, struct device *, void *));
70 int sermatch __P((struct device *, struct cfdata *, void *));
71
72 struct ser_softc {
73 struct device dev;
74 struct tty *ser_tty;
75 };
76
77 struct cfattach ser_ca = {
78 sizeof(struct ser_softc), sermatch, serattach
79 };
80
81 extern struct cfdriver ser_cd;
82
83 #ifndef SEROBUF_SIZE
84 #define SEROBUF_SIZE 32
85 #endif
86 #ifndef SERIBUF_SIZE
87 #define SERIBUF_SIZE 512
88 #endif
89
90 #define splser() spl5()
91
92 void serstart __P((struct tty *));
93 void ser_shutdown __P((struct ser_softc *));
94 int serparam __P((struct tty *, struct termios *));
95 void serintr __P((void));
96 int serhwiflow __P((struct tty *, int));
97 int sermctl __P((dev_t dev, int, int));
98 void ser_fastint __P((void));
99 void sereint __P((int));
100 static void ser_putchar __P((struct tty *, u_short));
101 void ser_outintr __P((void));
102 void sercnprobe __P((struct consdev *));
103 void sercninit __P((struct consdev *));
104 void serinit __P((int));
105 int sercngetc __P((dev_t dev));
106 void sercnputc __P((dev_t, int));
107 void sercnpollc __P((dev_t, int));
108
109 int nser = NSER;
110 #ifdef SERCONSOLE
111 int serconsole = SERCONSOLE;
112 #else
113 int serconsole = -1;
114 #endif
115 int serconsinit;
116 int serdefaultrate = TTYDEF_SPEED;
117 int sermajor;
118 int serswflags;
119
120 struct vbl_node ser_vbl_node;
121 struct tty ser_cons;
122 struct tty *ser_tty;
123
124 static u_short serbuf[SERIBUF_SIZE];
125 static u_short *sbrpt = serbuf;
126 static u_short *sbwpt = serbuf;
127 static u_short sbcnt;
128 static u_short sbovfl;
129 static u_char serdcd;
130
131 /*
132 * Since this UART is not particularly bright (to put it nicely), we'll
133 * have to do parity stuff on our own. This table contains the 8th bit
134 * in 7bit character mode, for even parity. If you want odd parity,
135 * flip the bit. (for generation of the table, see genpar.c)
136 */
137
138 u_char even_parity[] = {
139 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
140 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
141 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
142 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
143 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
144 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
145 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
146 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
147 };
148
149 /*
150 * Since we don't get interrupts for changes on the modem control line,
151 * we'll have to fake them by comparing current settings to the settings
152 * we remembered on last invocation.
153 */
154
155 u_char last_ciab_pra;
156
157 extern struct tty *constty;
158
159 extern int ser_open_speed; /* current speed of open serial device */
160
161 #ifdef KGDB
162 #include <machine/remote-sl.h>
163
164 extern dev_t kgdb_dev;
165 extern int kgdb_rate;
166 extern int kgdb_debug_init;
167 #endif
168
169 #ifdef DEBUG
170 long fifoin[17];
171 long fifoout[17];
172 long serintrcount[16];
173 long sermintcount[16];
174 #endif
175
176 void sermint __P((register int unit));
177
178 int
179 sermatch(pdp, cfp, auxp)
180 struct device *pdp;
181 struct cfdata *cfp;
182 void *auxp;
183 {
184
185 if (matchname("ser", (char *)auxp) == 0 || cfp->cf_unit != 0)
186 return(0);
187 if (serconsole != 0 && amiga_realconfig == 0)
188 return(0);
189 return(1);
190 }
191
192
193 void
194 serattach(pdp, dp, auxp)
195 struct device *pdp, *dp;
196 void *auxp;
197 {
198 struct ser_softc *sc;
199 struct tty *tp;
200 u_short ir;
201
202 sc = (struct ser_softc *)dp;
203
204 ir = custom.intenar;
205 if (serconsole == 0)
206 DELAY(100000);
207
208 ser_vbl_node.function = (void (*) (void *)) sermint;
209 add_vbl_function(&ser_vbl_node, SER_VBL_PRIORITY, (void *) 0);
210 #ifdef KGDB
211 if (kgdb_dev == makedev(sermajor, 0)) {
212 if (serconsole == 0)
213 kgdb_dev = NODEV; /* can't debug over console port */
214 else {
215 (void) serinit(kgdb_rate);
216 serconsinit = 1; /* don't re-init in serputc */
217 if (kgdb_debug_init == 0)
218 printf(" kgdb enabled\n");
219 else {
220 /*
221 * Print prefix of device name,
222 * let kgdb_connect print the rest.
223 */
224 printf("ser0: ");
225 kgdb_connect(1);
226 }
227 }
228 }
229 #endif
230 /*
231 * Need to reset baud rate, etc. of next print so reset serconsinit.
232 */
233 if (0 == serconsole)
234 serconsinit = 0;
235
236 tp = ttymalloc();
237 tp->t_oproc = (void (*) (struct tty *)) serstart;
238 tp->t_param = serparam;
239 tp->t_hwiflow = serhwiflow;
240 tty_attach(tp);
241 sc->ser_tty = ser_tty = tp;
242
243 if (dp)
244 printf(": input fifo %d output fifo %d\n", SERIBUF_SIZE,
245 SEROBUF_SIZE);
246 }
247
248
249 /* ARGSUSED */
250 int
251 seropen(dev, flag, mode, p)
252 dev_t dev;
253 int flag, mode;
254 struct proc *p;
255 {
256 struct ser_softc *sc;
257 struct tty *tp;
258 int unit, error, s, s2;
259
260 error = 0;
261 unit = SERUNIT(dev);
262
263 if (unit >= ser_cd.cd_ndevs)
264 return (ENXIO);
265
266 sc = ser_cd.cd_devs[unit];
267 if (sc == 0)
268 return (ENXIO);
269
270 /* XXX com.c: insert KGDB check here */
271
272 /* XXX ser.c had: s = spltty(); */
273
274 tp = sc->ser_tty;
275
276 if ((tp->t_state & TS_ISOPEN) &&
277 (tp->t_state & TS_XCLUDE) &&
278 p->p_ucred->cr_uid != 0)
279 return (EBUSY);
280
281 s = spltty();
282
283 /*
284 * If this is a first open...
285 */
286
287 if ((tp->t_state & TS_ISOPEN) == 0 && tp->t_wopen == 0) {
288 struct termios t;
289
290 tp->t_dev = dev;
291
292 s2 = splser();
293 /*
294 * XXX here: hw enable,
295 */
296 last_ciab_pra = ciab.pra;
297
298 splx(s2);
299 t.c_ispeed = 0;
300
301 /* XXX serconsolerate? */
302 t.c_ospeed = TTYDEF_SPEED;
303 t.c_cflag = TTYDEF_CFLAG;
304
305 if (serswflags & TIOCFLAG_CLOCAL)
306 t.c_cflag |= CLOCAL;
307 if (serswflags & TIOCFLAG_CRTSCTS)
308 t.c_cflag |= CRTSCTS;
309 if (serswflags & TIOCFLAG_MDMBUF)
310 t.c_cflag |= MDMBUF;
311
312 /* Make sure serparam() will do something. */
313 tp->t_ospeed = 0;
314 serparam(tp, &t);
315 tp->t_iflag = TTYDEF_IFLAG;
316 tp->t_oflag = TTYDEF_OFLAG;
317 tp->t_lflag = TTYDEF_LFLAG;
318 ttychars(tp);
319 ttsetwater(tp);
320
321 s2 = splser();
322 (void)sermctl(dev, TIOCM_DTR, DMSET);
323 /* clear input ring */
324 sbrpt = sbwpt = serbuf;
325 sbcnt = 0;
326 splx(s2);
327 }
328
329 splx(s);
330
331 error = ttyopen(tp, DIALOUT(dev), flag & O_NONBLOCK);
332 if (error)
333 goto bad;
334
335 error = (*linesw[tp->t_line].l_open)(dev, tp);
336 if (error)
337 goto bad;
338
339 return (0);
340
341 bad:
342 if (!(tp->t_state & TS_ISOPEN) && tp->t_wopen == 0) {
343 ser_shutdown(sc);
344 }
345
346 return (error);
347 }
348
349 /*ARGSUSED*/
350 int
351 serclose(dev, flag, mode, p)
352 dev_t dev;
353 int flag, mode;
354 struct proc *p;
355 {
356 struct ser_softc *sc;
357 struct tty *tp;
358
359 sc = ser_cd.cd_devs[0];
360 tp = ser_tty;
361
362 /* XXX This is for cons.c, according to com.c */
363 if (!(tp->t_state & TS_ISOPEN))
364 return (0);
365
366 (*linesw[tp->t_line].l_close)(tp, flag);
367 ttyclose(tp);
368
369 if (!(tp->t_state & TS_ISOPEN) && tp->t_wopen == 0) {
370 ser_shutdown(sc);
371 }
372 return (0);
373 }
374
375 void
376 ser_shutdown(sc)
377 struct ser_softc *sc;
378 {
379 struct tty *tp = sc->ser_tty;
380 int s;
381
382 s = splser();
383
384 custom.adkcon = ADKCONF_UARTBRK; /* clear break */
385 #if 0 /* XXX fix: #ifdef KGDB */
386 /*
387 * do not disable interrupts if debugging
388 */
389 if (dev != kgdb_dev)
390 #endif
391 custom.intena = INTF_RBF | INTF_TBE; /* disable interrupts */
392 custom.intreq = INTF_RBF | INTF_TBE; /* clear intr request */
393
394 /*
395 * If HUPCL is not set, leave DTR unchanged.
396 */
397 if (tp->t_cflag & HUPCL) {
398 (void)sermctl(tp->t_dev, TIOCM_DTR, DMBIC);
399 /*
400 * Idea from dev/ic/com.c:
401 * sleep a bit so that other side will notice, even if we
402 * reopen immediately.
403 */
404 (void) tsleep(tp, TTIPRI, ttclos, hz);
405 }
406
407 #if not_yet
408 if (tp != &ser_cons) {
409 remove_vbl_function(&ser_vbl_node);
410 ttyfree(tp);
411 ser_tty = (struct tty *) NULL;
412 }
413 #endif
414 ser_open_speed = tp->t_ispeed;
415 return;
416 }
417
418 int
419 serread(dev, uio, flag)
420 dev_t dev;
421 struct uio *uio;
422 int flag;
423 {
424 /* ARGSUSED */
425
426 return((*linesw[ser_tty->t_line].l_read)(ser_tty, uio, flag));
427 }
428
429 int
430 serwrite(dev, uio, flag)
431 dev_t dev;
432 struct uio *uio;
433 int flag;
434 {
435 /* ARGSUSED */
436
437 return((*linesw[ser_tty->t_line].l_write)(ser_tty, uio, flag));
438 }
439
440 struct tty *
441 sertty(dev)
442 dev_t dev;
443 {
444 /* ARGSUSED */
445
446 return (ser_tty);
447 }
448
449 /*
450 * We don't do any processing of data here, so we store the raw code
451 * obtained from the uart register. In theory, 110kBaud gives you
452 * 11kcps, so 16k buffer should be more than enough, interrupt
453 * latency of 1s should never happen, or something is seriously
454 * wrong..
455 * buffers moved to above seropen() -is
456 */
457
458 /*
459 * This is a replacement for the lack of a hardware fifo. 32k should be
460 * enough (there's only one unit anyway, so this is not going to
461 * accumulate).
462 */
463 void
464 ser_fastint()
465 {
466 /*
467 * We're at RBE-level, which is higher than VBL-level which is used
468 * to periodically transmit contents of this buffer up one layer,
469 * so no spl-raising is necessary.
470 */
471 u_short code;
472
473 /*
474 * This register contains both data and status bits!
475 */
476 code = custom.serdatr;
477
478 /*
479 * Use SERDATF_RBF instead of INTF_RBF; they're equivalent, but
480 * we save one (slow) custom chip access.
481 */
482 if ((code & SERDATRF_RBF) == 0)
483 return;
484
485 /*
486 * clear interrupt
487 */
488 custom.intreq = INTF_RBF;
489
490 /*
491 * check for buffer overflow.
492 */
493 if (sbcnt == SERIBUF_SIZE) {
494 ++sbovfl;
495 return;
496 }
497 /*
498 * store in buffer
499 */
500 *sbwpt++ = code;
501 if (sbwpt == serbuf + SERIBUF_SIZE)
502 sbwpt = serbuf;
503 ++sbcnt;
504 if (sbcnt > SERIBUF_SIZE - 20)
505 CLRRTS(ciab.pra); /* drop RTS if buffer almost full */
506 }
507
508
509 void
510 serintr()
511 {
512 int s1, s2, ovfl;
513 struct tty *tp = ser_tty;
514
515 /*
516 * Make sure we're not interrupted by another
517 * vbl, but allow level5 ints
518 */
519 s1 = spltty();
520
521 /*
522 * pass along any acumulated information
523 */
524 while (sbcnt > 0 && (tp->t_state & TS_TBLOCK) == 0) {
525 /*
526 * no collision with ser_fastint()
527 */
528 sereint(*sbrpt++);
529
530 ovfl = 0;
531 /* lock against ser_fastint() */
532 s2 = splser();
533 sbcnt--;
534 if (sbrpt == serbuf + SERIBUF_SIZE)
535 sbrpt = serbuf;
536 if (sbovfl != 0) {
537 ovfl = sbovfl;
538 sbovfl = 0;
539 }
540 splx(s2);
541 if (ovfl != 0)
542 log(LOG_WARNING, "ser0: %d ring buffer overflows.\n",
543 ovfl);
544 }
545 s2 = splser();
546 if (sbcnt == 0 && (tp->t_state & TS_TBLOCK) == 0)
547 SETRTS(ciab.pra); /* start accepting data again */
548 splx(s2);
549 splx(s1);
550 }
551
552 void
553 sereint(stat)
554 int stat;
555 {
556 struct tty *tp;
557 u_char ch;
558 int c;
559
560 tp = ser_tty;
561 ch = stat & 0xff;
562 c = ch;
563
564 if ((tp->t_state & TS_ISOPEN) == 0) {
565 #ifdef KGDB
566 /* we don't care about parity errors */
567 if (kgdb_dev == makedev(sermajor, 0) && c == FRAME_END)
568 kgdb_connect(0); /* trap into kgdb */
569 #endif
570 return;
571 }
572
573 /*
574 * Check for break and (if enabled) parity error.
575 */
576 if ((stat & 0x1ff) == 0)
577 c |= TTY_FE;
578 else if ((tp->t_cflag & PARENB) &&
579 (((ch >> 7) + even_parity[ch & 0x7f]
580 + !!(tp->t_cflag & PARODD)) & 1))
581 c |= TTY_PE;
582
583 if (stat & SERDATRF_OVRUN)
584 log(LOG_WARNING, "ser0: silo overflow\n");
585
586 (*linesw[tp->t_line].l_rint)(c, tp);
587 }
588
589 /*
590 * This interrupt is periodically invoked in the vertical blank
591 * interrupt. It's used to keep track of the modem control lines
592 * and (new with the fast_int code) to move accumulated data
593 * up into the tty layer.
594 */
595 void
596 sermint(unit)
597 int unit;
598 {
599 struct tty *tp;
600 u_char stat, last, istat;
601
602 tp = ser_tty;
603 if (!tp)
604 return;
605
606 /*
607 if ((tp->t_state & TS_ISOPEN) == 0 || tp->t_wopen == 0) {
608 sbrpt = sbwpt = serbuf;
609 return;
610 }
611 */
612 /*
613 * empty buffer
614 */
615 serintr();
616
617 stat = ciab.pra;
618 last = last_ciab_pra;
619 last_ciab_pra = stat;
620
621 /*
622 * check whether any interesting signal changed state
623 */
624 istat = stat ^ last;
625
626 if (istat & serdcd) {
627 (*linesw[tp->t_line].l_modem)(tp, ISDCD(stat));
628 }
629
630 if ((istat & CIAB_PRA_CTS) && (tp->t_state & TS_ISOPEN) &&
631 (tp->t_cflag & CRTSCTS)) {
632 #if 0
633 /* the line is up and we want to do rts/cts flow control */
634 if (ISCTS(stat)) {
635 tp->t_state &= ~TS_TTSTOP;
636 ttstart(tp);
637 /* cause tbe-int if we were stuck there */
638 custom.intreq = INTF_SETCLR | INTF_TBE;
639 } else
640 tp->t_state |= TS_TTSTOP;
641 #else
642 /* do this on hardware level, not with tty driver */
643 if (ISCTS(stat)) {
644 tp->t_state &= ~TS_TTSTOP;
645 /* cause TBE interrupt */
646 custom.intreq = INTF_SETCLR | INTF_TBE;
647 }
648 #endif
649 }
650 }
651
652 int
653 serioctl(dev, cmd, data, flag, p)
654 dev_t dev;
655 u_long cmd;
656 caddr_t data;
657 int flag;
658 struct proc *p;
659 {
660 register struct tty *tp;
661 register int error;
662
663 tp = ser_tty;
664 if (!tp)
665 return ENXIO;
666
667 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
668 if (error >= 0)
669 return(error);
670
671 error = ttioctl(tp, cmd, data, flag, p);
672 if (error >= 0)
673 return(error);
674
675 switch (cmd) {
676 case TIOCSBRK:
677 custom.adkcon = ADKCONF_SETCLR | ADKCONF_UARTBRK;
678 break;
679
680 case TIOCCBRK:
681 custom.adkcon = ADKCONF_UARTBRK;
682 break;
683
684 case TIOCSDTR:
685 (void) sermctl(dev, TIOCM_DTR, DMBIS);
686 break;
687
688 case TIOCCDTR:
689 (void) sermctl(dev, TIOCM_DTR, DMBIC);
690 break;
691
692 case TIOCMSET:
693 (void) sermctl(dev, *(int *) data, DMSET);
694 break;
695
696 case TIOCMBIS:
697 (void) sermctl(dev, *(int *) data, DMBIS);
698 break;
699
700 case TIOCMBIC:
701 (void) sermctl(dev, *(int *) data, DMBIC);
702 break;
703
704 case TIOCMGET:
705 *(int *)data = sermctl(dev, 0, DMGET);
706 break;
707 case TIOCGFLAGS:
708 *(int *)data = serswflags;
709 break;
710 case TIOCSFLAGS:
711 error = suser(p->p_ucred, &p->p_acflag);
712 if (error != 0)
713 return(EPERM);
714
715 serswflags = *(int *)data;
716 serswflags &= /* only allow valid flags */
717 (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
718 break;
719 default:
720 return(ENOTTY);
721 }
722
723 return(0);
724 }
725
726 int
727 serparam(tp, t)
728 struct tty *tp;
729 struct termios *t;
730 {
731 int cflag, ospeed = 0;
732
733 if (t->c_ospeed > 0) {
734 if (t->c_ospeed < 110)
735 return(EINVAL);
736 ospeed = SERBRD(t->c_ospeed);
737 }
738
739 if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
740 return(EINVAL);
741
742 /* XXX missing here: console test */
743 if (serswflags & TIOCFLAG_SOFTCAR) {
744 t->c_cflag = (t->c_cflag & ~HUPCL) | CLOCAL;
745 }
746
747 /* if no changes, dont do anything. com.c explains why. */
748 if (tp->t_ospeed == t->c_ospeed &&
749 tp->t_cflag == t->c_cflag)
750 return (0);
751
752 cflag = t->c_cflag;
753
754 if (cflag & (CLOCAL | MDMBUF))
755 serdcd = 0;
756 else
757 serdcd = CIAB_PRA_CD;
758
759 /* TODO: support multiple flow control protocols like com.c */
760
761 /*
762 * copy to tty
763 */
764 tp->t_ispeed = t->c_ispeed;
765 tp->t_ospeed = t->c_ospeed;
766 tp->t_cflag = cflag;
767 ser_open_speed = tp->t_ispeed;
768
769 /*
770 * enable interrupts
771 */
772 custom.intena = INTF_SETCLR | INTF_RBF | INTF_TBE;
773 last_ciab_pra = ciab.pra;
774
775 if (t->c_ospeed == 0)
776 (void)sermctl(tp->t_dev, 0, DMSET); /* hang up line */
777 else {
778 /*
779 * (re)enable DTR
780 * and set baud rate. (8 bit mode)
781 */
782 (void)sermctl(tp->t_dev, TIOCM_DTR, DMSET);
783 custom.serper = (0 << 15) | ospeed;
784 }
785 (void)(*linesw[tp->t_line].l_modem)(tp, ISDCD(last_ciab_pra));
786
787 return(0);
788 }
789
790 int serhwiflow(tp, flag)
791 struct tty *tp;
792 int flag;
793 {
794 #if 0
795 printf ("serhwiflow %d\n", flag);
796 #endif
797 if (flag)
798 CLRRTS(ciab.pra);
799 else
800 SETRTS(ciab.pra);
801 return 1;
802 }
803
804 static void
805 ser_putchar(tp, c)
806 struct tty *tp;
807 u_short c;
808 {
809 if ((tp->t_cflag & CSIZE) == CS7 || (tp->t_cflag & PARENB))
810 c &= 0x7f;
811
812 /*
813 * handle parity if necessary
814 */
815 if (tp->t_cflag & PARENB) {
816 if (even_parity[c])
817 c |= 0x80;
818 if (tp->t_cflag & PARODD)
819 c ^= 0x80;
820 }
821 /*
822 * add stop bit(s)
823 */
824 if (tp->t_cflag & CSTOPB)
825 c |= 0x300;
826 else
827 c |= 0x100;
828
829 custom.serdat = c;
830 }
831
832
833 static u_char ser_outbuf[SEROBUF_SIZE];
834 static u_char *sob_ptr = ser_outbuf, *sob_end = ser_outbuf;
835
836 void
837 ser_outintr()
838 {
839 struct tty *tp;
840 int s;
841
842 tp = ser_tty;
843 s = spltty();
844
845 if (tp == 0)
846 goto out;
847
848 if ((custom.intreqr & INTF_TBE) == 0)
849 goto out;
850
851 /*
852 * clear interrupt
853 */
854 custom.intreq = INTF_TBE;
855
856 if (sob_ptr == sob_end) {
857 tp->t_state &= ~(TS_BUSY | TS_FLUSH);
858 if (tp->t_line)
859 (*linesw[tp->t_line].l_start)(tp);
860 else
861 serstart(tp);
862 goto out;
863 }
864
865 /*
866 * Do hardware flow control here. if the CTS line goes down, don't
867 * transmit anything. That way, we'll be restarted by the periodic
868 * interrupt when CTS comes back up.
869 */
870 if (ISCTS(ciab.pra))
871 ser_putchar(tp, *sob_ptr++);
872 else
873 CLRCTS(last_ciab_pra); /* Remember that CTS is off */
874 out:
875 splx(s);
876 }
877
878 void
879 serstart(tp)
880 struct tty *tp;
881 {
882 int cc, s, hiwat;
883 #ifdef DIAGNOSTIC
884 int unit;
885 #endif
886
887 hiwat = 0;
888
889 if ((tp->t_state & TS_ISOPEN) == 0)
890 return;
891
892 #ifdef DIAGNOSTIC
893 unit = SERUNIT(tp->t_dev);
894 if (unit)
895 panic("serstart: unit is %d\n", unit);
896 #endif
897
898 s = spltty();
899 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
900 goto out;
901
902 cc = tp->t_outq.c_cc;
903 if (cc <= tp->t_lowat) {
904 if (tp->t_state & TS_ASLEEP) {
905 tp->t_state &= ~TS_ASLEEP;
906 wakeup((caddr_t) & tp->t_outq);
907 }
908 selwakeup(&tp->t_wsel);
909 }
910 if (cc == 0 || (tp->t_state & TS_BUSY))
911 goto out;
912
913 /*
914 * We only do bulk transfers if using CTSRTS flow control, not for
915 * (probably sloooow) ixon/ixoff devices.
916 */
917 if ((tp->t_cflag & CRTSCTS) == 0)
918 cc = 1;
919
920 /*
921 * Limit the amount of output we do in one burst
922 * to prevent hogging the CPU.
923 */
924 if (cc > SEROBUF_SIZE) {
925 hiwat++;
926 cc = SEROBUF_SIZE;
927 }
928 cc = q_to_b(&tp->t_outq, ser_outbuf, cc);
929 if (cc > 0) {
930 tp->t_state |= TS_BUSY;
931
932 sob_ptr = ser_outbuf;
933 sob_end = ser_outbuf + cc;
934
935 /*
936 * Get first character out, then have TBE-interrupts blow out
937 * further characters, until buffer is empty, and TS_BUSY gets
938 * cleared.
939 */
940 ser_putchar(tp, *sob_ptr++);
941 }
942 out:
943 splx(s);
944 }
945
946 /*
947 * Stop output on a line.
948 */
949 /*ARGSUSED*/
950 void
951 serstop(tp, flag)
952 struct tty *tp;
953 int flag;
954 {
955 int s;
956
957 s = spltty();
958 if (tp->t_state & TS_BUSY) {
959 if ((tp->t_state & TS_TTSTOP) == 0)
960 tp->t_state |= TS_FLUSH;
961 }
962 splx(s);
963 }
964
965 int
966 sermctl(dev, bits, how)
967 dev_t dev;
968 int bits, how;
969 {
970 int s;
971 u_char ub = 0;
972
973 /*
974 * convert TIOCM* mask into CIA mask
975 * which is active low
976 */
977 if (how != DMGET) {
978 ub = 0;
979 if (bits & TIOCM_DTR)
980 ub |= CIAB_PRA_DTR;
981 if (bits & TIOCM_RTS)
982 ub |= CIAB_PRA_RTS;
983 if (bits & TIOCM_CTS)
984 ub |= CIAB_PRA_CTS;
985 if (bits & TIOCM_CD)
986 ub |= CIAB_PRA_CD;
987 if (bits & TIOCM_RI)
988 ub |= CIAB_PRA_SEL; /* collision with /dev/par ! */
989 if (bits & TIOCM_DSR)
990 ub |= CIAB_PRA_DSR;
991 }
992 s = spltty();
993 switch (how) {
994 case DMSET:
995 /* invert and set */
996 ciab.pra = ~ub;
997 break;
998
999 case DMBIC:
1000 ciab.pra |= ub;
1001 ub = ~ciab.pra;
1002 break;
1003
1004 case DMBIS:
1005 ciab.pra &= ~ub;
1006 ub = ~ciab.pra;
1007 break;
1008
1009 case DMGET:
1010 ub = ~ciab.pra;
1011 break;
1012 }
1013 (void)splx(s);
1014
1015 bits = 0;
1016 if (ub & CIAB_PRA_DTR)
1017 bits |= TIOCM_DTR;
1018 if (ub & CIAB_PRA_RTS)
1019 bits |= TIOCM_RTS;
1020 if (ub & CIAB_PRA_CTS)
1021 bits |= TIOCM_CTS;
1022 if (ub & CIAB_PRA_CD)
1023 bits |= TIOCM_CD;
1024 if (ub & CIAB_PRA_SEL)
1025 bits |= TIOCM_RI;
1026 if (ub & CIAB_PRA_DSR)
1027 bits |= TIOCM_DSR;
1028
1029 return(bits);
1030 }
1031
1032 /*
1033 * Following are all routines needed for SER to act as console
1034 */
1035 void
1036 sercnprobe(cp)
1037 struct consdev *cp;
1038 {
1039 int unit;
1040
1041 /* locate the major number */
1042 for (sermajor = 0; sermajor < nchrdev; sermajor++)
1043 if (cdevsw[sermajor].d_open == (void *)seropen)
1044 break;
1045
1046
1047 unit = CONUNIT; /* XXX: ick */
1048
1049 /*
1050 * initialize required fields
1051 */
1052 cp->cn_dev = makedev(sermajor, unit);
1053 if (serconsole == unit)
1054 cp->cn_pri = CN_REMOTE;
1055 else
1056 cp->cn_pri = CN_NORMAL;
1057 #ifdef KGDB
1058 if (major(kgdb_dev) == 1) /* XXX */
1059 kgdb_dev = makedev(sermajor, minor(kgdb_dev));
1060 #endif
1061 }
1062
1063 void
1064 sercninit(cp)
1065 struct consdev *cp;
1066 {
1067 int unit;
1068
1069 unit = SERUNIT(cp->cn_dev);
1070
1071 serinit(serdefaultrate);
1072 serconsole = unit;
1073 serconsinit = 1;
1074 }
1075
1076 void
1077 serinit(rate)
1078 int rate;
1079 {
1080 int s;
1081
1082 s = splser();
1083 /*
1084 * might want to fiddle with the CIA later ???
1085 */
1086 custom.serper = (rate>=110 ? SERBRD(rate) : 0);
1087 splx(s);
1088 }
1089
1090 int
1091 sercngetc(dev)
1092 dev_t dev;
1093 {
1094 u_short stat;
1095 int c, s;
1096
1097 s = splser();
1098 /*
1099 * poll
1100 */
1101 while (((stat = custom.serdatr & 0xffff) & SERDATRF_RBF) == 0)
1102 ;
1103 c = stat & 0xff;
1104 /*
1105 * clear interrupt
1106 */
1107 custom.intreq = INTF_RBF;
1108 splx(s);
1109 return(c);
1110 }
1111
1112 /*
1113 * Console kernel output character routine.
1114 */
1115 void
1116 sercnputc(dev, c)
1117 dev_t dev;
1118 int c;
1119 {
1120 register int timo;
1121 int s;
1122
1123 s = splhigh();
1124
1125 if (serconsinit == 0) {
1126 (void)serinit(serdefaultrate);
1127 serconsinit = 1;
1128 }
1129
1130 /*
1131 * wait for any pending transmission to finish
1132 */
1133 timo = 50000;
1134 while (!(custom.serdatr & SERDATRF_TBE) && --timo);
1135
1136 /*
1137 * transmit char.
1138 */
1139 custom.serdat = (c & 0xff) | 0x100;
1140
1141 /*
1142 * wait for this transmission to complete
1143 */
1144 timo = 1500000;
1145 while (!(custom.serdatr & SERDATRF_TBE) && --timo)
1146 ;
1147
1148 /*
1149 * Wait for the device (my vt100..) to process the data, since we
1150 * don't do flow-control with cnputc
1151 */
1152 for (timo = 0; timo < 30000; timo++)
1153 ;
1154
1155 /*
1156 * clear any interrupts generated by this transmission
1157 */
1158 custom.intreq = INTF_TBE;
1159 splx(s);
1160 }
1161
1162 void
1163 sercnpollc(dev, on)
1164 dev_t dev;
1165 int on;
1166 {
1167 }
1168 #endif
1169