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