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