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