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