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