ser.c revision 1.44 1 /* $NetBSD: ser.c,v 1.44 1998/04/11 19:30:56 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 * fetch current modem control status
296 */
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 | TIOCM_RTS, 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 | TIOCM_RTS, DMSET);
781 custom.serper = (0 << 15) | ospeed;
782 }
783 return(0);
784 }
785
786 int serhwiflow(tp, flag)
787 struct tty *tp;
788 int flag;
789 {
790 #if 0
791 printf ("serhwiflow %d\n", flag);
792 #endif
793 if (flag)
794 CLRRTS(ciab.pra);
795 else
796 SETRTS(ciab.pra);
797 return 1;
798 }
799
800 static void
801 ser_putchar(tp, c)
802 struct tty *tp;
803 u_short c;
804 {
805 if ((tp->t_cflag & CSIZE) == CS7 || (tp->t_cflag & PARENB))
806 c &= 0x7f;
807
808 /*
809 * handle parity if necessary
810 */
811 if (tp->t_cflag & PARENB) {
812 if (even_parity[c])
813 c |= 0x80;
814 if (tp->t_cflag & PARODD)
815 c ^= 0x80;
816 }
817 /*
818 * add stop bit(s)
819 */
820 if (tp->t_cflag & CSTOPB)
821 c |= 0x300;
822 else
823 c |= 0x100;
824
825 custom.serdat = c;
826 }
827
828
829 static u_char ser_outbuf[SEROBUF_SIZE];
830 static u_char *sob_ptr = ser_outbuf, *sob_end = ser_outbuf;
831
832 void
833 ser_outintr()
834 {
835 struct tty *tp;
836 int s;
837
838 tp = ser_tty;
839 s = spltty();
840
841 if (tp == 0)
842 goto out;
843
844 if ((custom.intreqr & INTF_TBE) == 0)
845 goto out;
846
847 /*
848 * clear interrupt
849 */
850 custom.intreq = INTF_TBE;
851
852 if (sob_ptr == sob_end) {
853 tp->t_state &= ~(TS_BUSY | TS_FLUSH);
854 if (tp->t_line)
855 (*linesw[tp->t_line].l_start)(tp);
856 else
857 serstart(tp);
858 goto out;
859 }
860
861 /*
862 * Do hardware flow control here. if the CTS line goes down, don't
863 * transmit anything. That way, we'll be restarted by the periodic
864 * interrupt when CTS comes back up.
865 */
866 if (ISCTS(ciab.pra))
867 ser_putchar(tp, *sob_ptr++);
868 else
869 CLRCTS(last_ciab_pra); /* Remember that CTS is off */
870 out:
871 splx(s);
872 }
873
874 void
875 serstart(tp)
876 struct tty *tp;
877 {
878 int cc, s, hiwat;
879 #ifdef DIAGNOSTIC
880 int unit;
881 #endif
882
883 hiwat = 0;
884
885 if ((tp->t_state & TS_ISOPEN) == 0)
886 return;
887
888 #ifdef DIAGNOSTIC
889 unit = SERUNIT(tp->t_dev);
890 if (unit)
891 panic("serstart: unit is %d\n", unit);
892 #endif
893
894 s = spltty();
895 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
896 goto out;
897
898 cc = tp->t_outq.c_cc;
899 if (cc <= tp->t_lowat) {
900 if (tp->t_state & TS_ASLEEP) {
901 tp->t_state &= ~TS_ASLEEP;
902 wakeup((caddr_t) & tp->t_outq);
903 }
904 selwakeup(&tp->t_wsel);
905 }
906 if (cc == 0 || (tp->t_state & TS_BUSY))
907 goto out;
908
909 /*
910 * We only do bulk transfers if using CTSRTS flow control, not for
911 * (probably sloooow) ixon/ixoff devices.
912 */
913 if ((tp->t_cflag & CRTSCTS) == 0)
914 cc = 1;
915
916 /*
917 * Limit the amount of output we do in one burst
918 * to prevent hogging the CPU.
919 */
920 if (cc > SEROBUF_SIZE) {
921 hiwat++;
922 cc = SEROBUF_SIZE;
923 }
924 cc = q_to_b(&tp->t_outq, ser_outbuf, cc);
925 if (cc > 0) {
926 tp->t_state |= TS_BUSY;
927
928 sob_ptr = ser_outbuf;
929 sob_end = ser_outbuf + cc;
930
931 /*
932 * Get first character out, then have TBE-interrupts blow out
933 * further characters, until buffer is empty, and TS_BUSY gets
934 * cleared.
935 */
936 ser_putchar(tp, *sob_ptr++);
937 }
938 out:
939 splx(s);
940 }
941
942 /*
943 * Stop output on a line.
944 */
945 /*ARGSUSED*/
946 void
947 serstop(tp, flag)
948 struct tty *tp;
949 int flag;
950 {
951 int s;
952
953 s = spltty();
954 if (tp->t_state & TS_BUSY) {
955 if ((tp->t_state & TS_TTSTOP) == 0)
956 tp->t_state |= TS_FLUSH;
957 }
958 splx(s);
959 }
960
961 int
962 sermctl(dev, bits, how)
963 dev_t dev;
964 int bits, how;
965 {
966 int s;
967 u_char ub = 0;
968
969 /*
970 * convert TIOCM* mask into CIA mask
971 * which is active low
972 */
973 if (how != DMGET) {
974 ub = 0;
975 if (bits & TIOCM_DTR)
976 ub |= CIAB_PRA_DTR;
977 if (bits & TIOCM_RTS)
978 ub |= CIAB_PRA_RTS;
979 if (bits & TIOCM_CTS)
980 ub |= CIAB_PRA_CTS;
981 if (bits & TIOCM_CD)
982 ub |= CIAB_PRA_CD;
983 if (bits & TIOCM_RI)
984 ub |= CIAB_PRA_SEL; /* collision with /dev/par ! */
985 if (bits & TIOCM_DSR)
986 ub |= CIAB_PRA_DSR;
987 }
988 s = spltty();
989 switch (how) {
990 case DMSET:
991 /* invert and set */
992 ciab.pra = ~ub;
993 break;
994
995 case DMBIC:
996 ciab.pra |= ub;
997 ub = ~ciab.pra;
998 break;
999
1000 case DMBIS:
1001 ciab.pra &= ~ub;
1002 ub = ~ciab.pra;
1003 break;
1004
1005 case DMGET:
1006 ub = ~ciab.pra;
1007 break;
1008 }
1009 (void)splx(s);
1010
1011 bits = 0;
1012 if (ub & CIAB_PRA_DTR)
1013 bits |= TIOCM_DTR;
1014 if (ub & CIAB_PRA_RTS)
1015 bits |= TIOCM_RTS;
1016 if (ub & CIAB_PRA_CTS)
1017 bits |= TIOCM_CTS;
1018 if (ub & CIAB_PRA_CD)
1019 bits |= TIOCM_CD;
1020 if (ub & CIAB_PRA_SEL)
1021 bits |= TIOCM_RI;
1022 if (ub & CIAB_PRA_DSR)
1023 bits |= TIOCM_DSR;
1024
1025 return(bits);
1026 }
1027
1028 /*
1029 * Following are all routines needed for SER to act as console
1030 */
1031 void
1032 sercnprobe(cp)
1033 struct consdev *cp;
1034 {
1035 int unit;
1036
1037 /* locate the major number */
1038 for (sermajor = 0; sermajor < nchrdev; sermajor++)
1039 if (cdevsw[sermajor].d_open == (void *)seropen)
1040 break;
1041
1042
1043 unit = CONUNIT; /* XXX: ick */
1044
1045 /*
1046 * initialize required fields
1047 */
1048 cp->cn_dev = makedev(sermajor, unit);
1049 if (serconsole == unit)
1050 cp->cn_pri = CN_REMOTE;
1051 else
1052 cp->cn_pri = CN_NORMAL;
1053 #ifdef KGDB
1054 if (major(kgdb_dev) == 1) /* XXX */
1055 kgdb_dev = makedev(sermajor, minor(kgdb_dev));
1056 #endif
1057 }
1058
1059 void
1060 sercninit(cp)
1061 struct consdev *cp;
1062 {
1063 int unit;
1064
1065 unit = SERUNIT(cp->cn_dev);
1066
1067 serinit(serdefaultrate);
1068 serconsole = unit;
1069 serconsinit = 1;
1070 }
1071
1072 void
1073 serinit(rate)
1074 int rate;
1075 {
1076 int s;
1077
1078 s = splser();
1079 /*
1080 * might want to fiddle with the CIA later ???
1081 */
1082 custom.serper = (rate>=110 ? SERBRD(rate) : 0);
1083 splx(s);
1084 }
1085
1086 int
1087 sercngetc(dev)
1088 dev_t dev;
1089 {
1090 u_short stat;
1091 int c, s;
1092
1093 s = splser();
1094 /*
1095 * poll
1096 */
1097 while (((stat = custom.serdatr & 0xffff) & SERDATRF_RBF) == 0)
1098 ;
1099 c = stat & 0xff;
1100 /*
1101 * clear interrupt
1102 */
1103 custom.intreq = INTF_RBF;
1104 splx(s);
1105 return(c);
1106 }
1107
1108 /*
1109 * Console kernel output character routine.
1110 */
1111 void
1112 sercnputc(dev, c)
1113 dev_t dev;
1114 int c;
1115 {
1116 register int timo;
1117 int s;
1118
1119 s = splhigh();
1120
1121 if (serconsinit == 0) {
1122 (void)serinit(serdefaultrate);
1123 serconsinit = 1;
1124 }
1125
1126 /*
1127 * wait for any pending transmission to finish
1128 */
1129 timo = 50000;
1130 while (!(custom.serdatr & SERDATRF_TBE) && --timo);
1131
1132 /*
1133 * transmit char.
1134 */
1135 custom.serdat = (c & 0xff) | 0x100;
1136
1137 /*
1138 * wait for this transmission to complete
1139 */
1140 timo = 1500000;
1141 while (!(custom.serdatr & SERDATRF_TBE) && --timo)
1142 ;
1143
1144 /*
1145 * Wait for the device (my vt100..) to process the data, since we
1146 * don't do flow-control with cnputc
1147 */
1148 for (timo = 0; timo < 30000; timo++)
1149 ;
1150
1151 /*
1152 * clear any interrupts generated by this transmission
1153 */
1154 custom.intreq = INTF_TBE;
1155 splx(s);
1156 }
1157
1158 void
1159 sercnpollc(dev, on)
1160 dev_t dev;
1161 int on;
1162 {
1163 }
1164 #endif
1165