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