ser.c revision 1.46 1 /* $NetBSD: ser.c,v 1.46 1998/06/29 19:31:19 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 register u_short ints, code;
472
473 /* XXX should this ever happen? */
474 ints = custom.intreqr & INTF_RBF;
475 if (ints == 0)
476 return;
477
478 /*
479 * this register contains both data and status bits!
480 */
481 code = custom.serdatr;
482
483 /*
484 * clear interrupt
485 */
486 custom.intreq = INTF_RBF;
487
488 /*
489 * check for buffer overflow.
490 */
491 if (sbcnt == SERIBUF_SIZE) {
492 ++sbovfl;
493 return;
494 }
495 /*
496 * store in buffer
497 */
498 *sbwpt++ = code;
499 if (sbwpt == serbuf + SERIBUF_SIZE)
500 sbwpt = serbuf;
501 ++sbcnt;
502 if (sbcnt > SERIBUF_SIZE - 20)
503 CLRRTS(ciab.pra); /* drop RTS if buffer almost full */
504 }
505
506
507 void
508 serintr()
509 {
510 int s1, s2, ovfl;
511 struct tty *tp = ser_tty;
512
513 /*
514 * Make sure we're not interrupted by another
515 * vbl, but allow level5 ints
516 */
517 s1 = spltty();
518
519 /*
520 * pass along any acumulated information
521 */
522 while (sbcnt > 0 && (tp->t_state & TS_TBLOCK) == 0) {
523 /*
524 * no collision with ser_fastint()
525 */
526 sereint(*sbrpt++);
527
528 ovfl = 0;
529 /* lock against ser_fastint() */
530 s2 = splser();
531 sbcnt--;
532 if (sbrpt == serbuf + SERIBUF_SIZE)
533 sbrpt = serbuf;
534 if (sbovfl != 0) {
535 ovfl = sbovfl;
536 sbovfl = 0;
537 }
538 splx(s2);
539 if (ovfl != 0)
540 log(LOG_WARNING, "ser0: %d ring buffer overflows.\n",
541 ovfl);
542 }
543 s2 = splser();
544 if (sbcnt == 0 && (tp->t_state & TS_TBLOCK) == 0)
545 SETRTS(ciab.pra); /* start accepting data again */
546 splx(s2);
547 splx(s1);
548 }
549
550 void
551 sereint(stat)
552 int stat;
553 {
554 struct tty *tp;
555 u_char ch;
556 int c;
557
558 tp = ser_tty;
559 ch = stat & 0xff;
560 c = ch;
561
562 if ((tp->t_state & TS_ISOPEN) == 0) {
563 #ifdef KGDB
564 /* we don't care about parity errors */
565 if (kgdb_dev == makedev(sermajor, 0) && c == FRAME_END)
566 kgdb_connect(0); /* trap into kgdb */
567 #endif
568 return;
569 }
570
571 /*
572 * Check for break and (if enabled) parity error.
573 */
574 if ((stat & 0x1ff) == 0)
575 c |= TTY_FE;
576 else if ((tp->t_cflag & PARENB) &&
577 (((ch >> 7) + even_parity[ch & 0x7f]
578 + !!(tp->t_cflag & PARODD)) & 1))
579 c |= TTY_PE;
580
581 if (stat & SERDATRF_OVRUN)
582 log(LOG_WARNING, "ser0: silo overflow\n");
583
584 (*linesw[tp->t_line].l_rint)(c, tp);
585 }
586
587 /*
588 * This interrupt is periodically invoked in the vertical blank
589 * interrupt. It's used to keep track of the modem control lines
590 * and (new with the fast_int code) to move accumulated data
591 * up into the tty layer.
592 */
593 void
594 sermint(unit)
595 int unit;
596 {
597 struct tty *tp;
598 u_char stat, last, istat;
599
600 tp = ser_tty;
601 if (!tp)
602 return;
603
604 /*
605 if ((tp->t_state & TS_ISOPEN) == 0 || tp->t_wopen == 0) {
606 sbrpt = sbwpt = serbuf;
607 return;
608 }
609 */
610 /*
611 * empty buffer
612 */
613 serintr();
614
615 stat = ciab.pra;
616 last = last_ciab_pra;
617 last_ciab_pra = stat;
618
619 /*
620 * check whether any interesting signal changed state
621 */
622 istat = stat ^ last;
623
624 if (istat & serdcd) {
625 (*linesw[tp->t_line].l_modem)(tp, ISDCD(stat));
626 }
627
628 if ((istat & CIAB_PRA_CTS) && (tp->t_state & TS_ISOPEN) &&
629 (tp->t_cflag & CRTSCTS)) {
630 #if 0
631 /* the line is up and we want to do rts/cts flow control */
632 if (ISCTS(stat)) {
633 tp->t_state &= ~TS_TTSTOP;
634 ttstart(tp);
635 /* cause tbe-int if we were stuck there */
636 custom.intreq = INTF_SETCLR | INTF_TBE;
637 } else
638 tp->t_state |= TS_TTSTOP;
639 #else
640 /* do this on hardware level, not with tty driver */
641 if (ISCTS(stat)) {
642 tp->t_state &= ~TS_TTSTOP;
643 /* cause TBE interrupt */
644 custom.intreq = INTF_SETCLR | INTF_TBE;
645 }
646 #endif
647 }
648 }
649
650 int
651 serioctl(dev, cmd, data, flag, p)
652 dev_t dev;
653 u_long cmd;
654 caddr_t data;
655 int flag;
656 struct proc *p;
657 {
658 register struct tty *tp;
659 register int error;
660
661 tp = ser_tty;
662 if (!tp)
663 return ENXIO;
664
665 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
666 if (error >= 0)
667 return(error);
668
669 error = ttioctl(tp, cmd, data, flag, p);
670 if (error >= 0)
671 return(error);
672
673 switch (cmd) {
674 case TIOCSBRK:
675 custom.adkcon = ADKCONF_SETCLR | ADKCONF_UARTBRK;
676 break;
677
678 case TIOCCBRK:
679 custom.adkcon = ADKCONF_UARTBRK;
680 break;
681
682 case TIOCSDTR:
683 (void) sermctl(dev, TIOCM_DTR, DMBIS);
684 break;
685
686 case TIOCCDTR:
687 (void) sermctl(dev, TIOCM_DTR, DMBIC);
688 break;
689
690 case TIOCMSET:
691 (void) sermctl(dev, *(int *) data, DMSET);
692 break;
693
694 case TIOCMBIS:
695 (void) sermctl(dev, *(int *) data, DMBIS);
696 break;
697
698 case TIOCMBIC:
699 (void) sermctl(dev, *(int *) data, DMBIC);
700 break;
701
702 case TIOCMGET:
703 *(int *)data = sermctl(dev, 0, DMGET);
704 break;
705 case TIOCGFLAGS:
706 *(int *)data = serswflags;
707 break;
708 case TIOCSFLAGS:
709 error = suser(p->p_ucred, &p->p_acflag);
710 if (error != 0)
711 return(EPERM);
712
713 serswflags = *(int *)data;
714 serswflags &= /* only allow valid flags */
715 (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
716 break;
717 default:
718 return(ENOTTY);
719 }
720
721 return(0);
722 }
723
724 int
725 serparam(tp, t)
726 struct tty *tp;
727 struct termios *t;
728 {
729 int cflag, ospeed = 0;
730
731 if (t->c_ospeed > 0) {
732 if (t->c_ospeed < 110)
733 return(EINVAL);
734 ospeed = SERBRD(t->c_ospeed);
735 }
736
737 if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
738 return(EINVAL);
739
740 /* XXX missing here: console test */
741 if (serswflags & TIOCFLAG_SOFTCAR) {
742 t->c_cflag = (t->c_cflag & ~HUPCL) | CLOCAL;
743 }
744
745 /* if no changes, dont do anything. com.c explains why. */
746 if (tp->t_ospeed == t->c_ospeed &&
747 tp->t_cflag == t->c_cflag)
748 return (0);
749
750 cflag = t->c_cflag;
751
752 if (cflag & (CLOCAL | MDMBUF))
753 serdcd = 0;
754 else
755 serdcd = CIAB_PRA_CD;
756
757 /* TODO: support multiple flow control protocols like com.c */
758
759 /*
760 * copy to tty
761 */
762 tp->t_ispeed = t->c_ispeed;
763 tp->t_ospeed = t->c_ospeed;
764 tp->t_cflag = cflag;
765 ser_open_speed = tp->t_ispeed;
766
767 /*
768 * enable interrupts
769 */
770 custom.intena = INTF_SETCLR | INTF_RBF | INTF_TBE;
771 last_ciab_pra = ciab.pra;
772
773 if (t->c_ospeed == 0)
774 (void)sermctl(tp->t_dev, 0, DMSET); /* hang up line */
775 else {
776 /*
777 * (re)enable DTR
778 * and set baud rate. (8 bit mode)
779 */
780 (void)sermctl(tp->t_dev, TIOCM_DTR, DMSET);
781 custom.serper = (0 << 15) | ospeed;
782 }
783 (void)(*linesw[tp->t_line].l_modem)(tp, ISDCD(last_ciab_pra));
784
785 return(0);
786 }
787
788 int serhwiflow(tp, flag)
789 struct tty *tp;
790 int flag;
791 {
792 #if 0
793 printf ("serhwiflow %d\n", flag);
794 #endif
795 if (flag)
796 CLRRTS(ciab.pra);
797 else
798 SETRTS(ciab.pra);
799 return 1;
800 }
801
802 static void
803 ser_putchar(tp, c)
804 struct tty *tp;
805 u_short c;
806 {
807 if ((tp->t_cflag & CSIZE) == CS7 || (tp->t_cflag & PARENB))
808 c &= 0x7f;
809
810 /*
811 * handle parity if necessary
812 */
813 if (tp->t_cflag & PARENB) {
814 if (even_parity[c])
815 c |= 0x80;
816 if (tp->t_cflag & PARODD)
817 c ^= 0x80;
818 }
819 /*
820 * add stop bit(s)
821 */
822 if (tp->t_cflag & CSTOPB)
823 c |= 0x300;
824 else
825 c |= 0x100;
826
827 custom.serdat = c;
828 }
829
830
831 static u_char ser_outbuf[SEROBUF_SIZE];
832 static u_char *sob_ptr = ser_outbuf, *sob_end = ser_outbuf;
833
834 void
835 ser_outintr()
836 {
837 struct tty *tp;
838 int s;
839
840 tp = ser_tty;
841 s = spltty();
842
843 if (tp == 0)
844 goto out;
845
846 if ((custom.intreqr & INTF_TBE) == 0)
847 goto out;
848
849 /*
850 * clear interrupt
851 */
852 custom.intreq = INTF_TBE;
853
854 if (sob_ptr == sob_end) {
855 tp->t_state &= ~(TS_BUSY | TS_FLUSH);
856 if (tp->t_line)
857 (*linesw[tp->t_line].l_start)(tp);
858 else
859 serstart(tp);
860 goto out;
861 }
862
863 /*
864 * Do hardware flow control here. if the CTS line goes down, don't
865 * transmit anything. That way, we'll be restarted by the periodic
866 * interrupt when CTS comes back up.
867 */
868 if (ISCTS(ciab.pra))
869 ser_putchar(tp, *sob_ptr++);
870 else
871 CLRCTS(last_ciab_pra); /* Remember that CTS is off */
872 out:
873 splx(s);
874 }
875
876 void
877 serstart(tp)
878 struct tty *tp;
879 {
880 int cc, s, hiwat;
881 #ifdef DIAGNOSTIC
882 int unit;
883 #endif
884
885 hiwat = 0;
886
887 if ((tp->t_state & TS_ISOPEN) == 0)
888 return;
889
890 #ifdef DIAGNOSTIC
891 unit = SERUNIT(tp->t_dev);
892 if (unit)
893 panic("serstart: unit is %d\n", unit);
894 #endif
895
896 s = spltty();
897 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
898 goto out;
899
900 cc = tp->t_outq.c_cc;
901 if (cc <= tp->t_lowat) {
902 if (tp->t_state & TS_ASLEEP) {
903 tp->t_state &= ~TS_ASLEEP;
904 wakeup((caddr_t) & tp->t_outq);
905 }
906 selwakeup(&tp->t_wsel);
907 }
908 if (cc == 0 || (tp->t_state & TS_BUSY))
909 goto out;
910
911 /*
912 * We only do bulk transfers if using CTSRTS flow control, not for
913 * (probably sloooow) ixon/ixoff devices.
914 */
915 if ((tp->t_cflag & CRTSCTS) == 0)
916 cc = 1;
917
918 /*
919 * Limit the amount of output we do in one burst
920 * to prevent hogging the CPU.
921 */
922 if (cc > SEROBUF_SIZE) {
923 hiwat++;
924 cc = SEROBUF_SIZE;
925 }
926 cc = q_to_b(&tp->t_outq, ser_outbuf, cc);
927 if (cc > 0) {
928 tp->t_state |= TS_BUSY;
929
930 sob_ptr = ser_outbuf;
931 sob_end = ser_outbuf + cc;
932
933 /*
934 * Get first character out, then have TBE-interrupts blow out
935 * further characters, until buffer is empty, and TS_BUSY gets
936 * cleared.
937 */
938 ser_putchar(tp, *sob_ptr++);
939 }
940 out:
941 splx(s);
942 }
943
944 /*
945 * Stop output on a line.
946 */
947 /*ARGSUSED*/
948 void
949 serstop(tp, flag)
950 struct tty *tp;
951 int flag;
952 {
953 int s;
954
955 s = spltty();
956 if (tp->t_state & TS_BUSY) {
957 if ((tp->t_state & TS_TTSTOP) == 0)
958 tp->t_state |= TS_FLUSH;
959 }
960 splx(s);
961 }
962
963 int
964 sermctl(dev, bits, how)
965 dev_t dev;
966 int bits, how;
967 {
968 int s;
969 u_char ub = 0;
970
971 /*
972 * convert TIOCM* mask into CIA mask
973 * which is active low
974 */
975 if (how != DMGET) {
976 ub = 0;
977 if (bits & TIOCM_DTR)
978 ub |= CIAB_PRA_DTR;
979 if (bits & TIOCM_RTS)
980 ub |= CIAB_PRA_RTS;
981 if (bits & TIOCM_CTS)
982 ub |= CIAB_PRA_CTS;
983 if (bits & TIOCM_CD)
984 ub |= CIAB_PRA_CD;
985 if (bits & TIOCM_RI)
986 ub |= CIAB_PRA_SEL; /* collision with /dev/par ! */
987 if (bits & TIOCM_DSR)
988 ub |= CIAB_PRA_DSR;
989 }
990 s = spltty();
991 switch (how) {
992 case DMSET:
993 /* invert and set */
994 ciab.pra = ~ub;
995 break;
996
997 case DMBIC:
998 ciab.pra |= ub;
999 ub = ~ciab.pra;
1000 break;
1001
1002 case DMBIS:
1003 ciab.pra &= ~ub;
1004 ub = ~ciab.pra;
1005 break;
1006
1007 case DMGET:
1008 ub = ~ciab.pra;
1009 break;
1010 }
1011 (void)splx(s);
1012
1013 bits = 0;
1014 if (ub & CIAB_PRA_DTR)
1015 bits |= TIOCM_DTR;
1016 if (ub & CIAB_PRA_RTS)
1017 bits |= TIOCM_RTS;
1018 if (ub & CIAB_PRA_CTS)
1019 bits |= TIOCM_CTS;
1020 if (ub & CIAB_PRA_CD)
1021 bits |= TIOCM_CD;
1022 if (ub & CIAB_PRA_SEL)
1023 bits |= TIOCM_RI;
1024 if (ub & CIAB_PRA_DSR)
1025 bits |= TIOCM_DSR;
1026
1027 return(bits);
1028 }
1029
1030 /*
1031 * Following are all routines needed for SER to act as console
1032 */
1033 void
1034 sercnprobe(cp)
1035 struct consdev *cp;
1036 {
1037 int unit;
1038
1039 /* locate the major number */
1040 for (sermajor = 0; sermajor < nchrdev; sermajor++)
1041 if (cdevsw[sermajor].d_open == (void *)seropen)
1042 break;
1043
1044
1045 unit = CONUNIT; /* XXX: ick */
1046
1047 /*
1048 * initialize required fields
1049 */
1050 cp->cn_dev = makedev(sermajor, unit);
1051 if (serconsole == unit)
1052 cp->cn_pri = CN_REMOTE;
1053 else
1054 cp->cn_pri = CN_NORMAL;
1055 #ifdef KGDB
1056 if (major(kgdb_dev) == 1) /* XXX */
1057 kgdb_dev = makedev(sermajor, minor(kgdb_dev));
1058 #endif
1059 }
1060
1061 void
1062 sercninit(cp)
1063 struct consdev *cp;
1064 {
1065 int unit;
1066
1067 unit = SERUNIT(cp->cn_dev);
1068
1069 serinit(serdefaultrate);
1070 serconsole = unit;
1071 serconsinit = 1;
1072 }
1073
1074 void
1075 serinit(rate)
1076 int rate;
1077 {
1078 int s;
1079
1080 s = splser();
1081 /*
1082 * might want to fiddle with the CIA later ???
1083 */
1084 custom.serper = (rate>=110 ? SERBRD(rate) : 0);
1085 splx(s);
1086 }
1087
1088 int
1089 sercngetc(dev)
1090 dev_t dev;
1091 {
1092 u_short stat;
1093 int c, s;
1094
1095 s = splser();
1096 /*
1097 * poll
1098 */
1099 while (((stat = custom.serdatr & 0xffff) & SERDATRF_RBF) == 0)
1100 ;
1101 c = stat & 0xff;
1102 /*
1103 * clear interrupt
1104 */
1105 custom.intreq = INTF_RBF;
1106 splx(s);
1107 return(c);
1108 }
1109
1110 /*
1111 * Console kernel output character routine.
1112 */
1113 void
1114 sercnputc(dev, c)
1115 dev_t dev;
1116 int c;
1117 {
1118 register int timo;
1119 int s;
1120
1121 s = splhigh();
1122
1123 if (serconsinit == 0) {
1124 (void)serinit(serdefaultrate);
1125 serconsinit = 1;
1126 }
1127
1128 /*
1129 * wait for any pending transmission to finish
1130 */
1131 timo = 50000;
1132 while (!(custom.serdatr & SERDATRF_TBE) && --timo);
1133
1134 /*
1135 * transmit char.
1136 */
1137 custom.serdat = (c & 0xff) | 0x100;
1138
1139 /*
1140 * wait for this transmission to complete
1141 */
1142 timo = 1500000;
1143 while (!(custom.serdatr & SERDATRF_TBE) && --timo)
1144 ;
1145
1146 /*
1147 * Wait for the device (my vt100..) to process the data, since we
1148 * don't do flow-control with cnputc
1149 */
1150 for (timo = 0; timo < 30000; timo++)
1151 ;
1152
1153 /*
1154 * clear any interrupts generated by this transmission
1155 */
1156 custom.intreq = INTF_TBE;
1157 splx(s);
1158 }
1159
1160 void
1161 sercnpollc(dev, on)
1162 dev_t dev;
1163 int on;
1164 {
1165 }
1166 #endif
1167