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