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