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