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