ser.c revision 1.36 1 /* $NetBSD: ser.c,v 1.36 1996/09/02 06:43:33 mycroft 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 void
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 }
908
909 int
910 sermctl(dev, bits, how)
911 dev_t dev;
912 int bits, how;
913 {
914 int unit, s;
915 u_char ub = 0;
916
917 unit = SERUNIT(dev);
918
919 /*
920 * convert TIOCM* mask into CIA mask
921 * which is active low
922 */
923 if (how != DMGET) {
924 ub = 0;
925 if (bits & TIOCM_DTR)
926 ub |= CIAB_PRA_DTR;
927 if (bits & TIOCM_RTS)
928 ub |= CIAB_PRA_RTS;
929 if (bits & TIOCM_CTS)
930 ub |= CIAB_PRA_CTS;
931 if (bits & TIOCM_CD)
932 ub |= CIAB_PRA_CD;
933 if (bits & TIOCM_RI)
934 ub |= CIAB_PRA_SEL; /* collision with /dev/par ! */
935 if (bits & TIOCM_DSR)
936 ub |= CIAB_PRA_DSR;
937 }
938 s = spltty();
939 switch (how) {
940 case DMSET:
941 /* invert and set */
942 ciab.pra = ~ub;
943 break;
944
945 case DMBIC:
946 ciab.pra |= ub;
947 ub = ~ciab.pra;
948 break;
949
950 case DMBIS:
951 ciab.pra &= ~ub;
952 ub = ~ciab.pra;
953 break;
954
955 case DMGET:
956 ub = ~ciab.pra;
957 break;
958 }
959 (void)splx(s);
960
961 bits = 0;
962 if (ub & CIAB_PRA_DTR)
963 bits |= TIOCM_DTR;
964 if (ub & CIAB_PRA_RTS)
965 bits |= TIOCM_RTS;
966 if (ub & CIAB_PRA_CTS)
967 bits |= TIOCM_CTS;
968 if (ub & CIAB_PRA_CD)
969 bits |= TIOCM_CD;
970 if (ub & CIAB_PRA_SEL)
971 bits |= TIOCM_RI;
972 if (ub & CIAB_PRA_DSR)
973 bits |= TIOCM_DSR;
974
975 return(bits);
976 }
977
978 /*
979 * Following are all routines needed for SER to act as console
980 */
981 void
982 sercnprobe(cp)
983 struct consdev *cp;
984 {
985 int unit = CONUNIT;
986
987 /* locate the major number */
988 for (sermajor = 0; sermajor < nchrdev; sermajor++)
989 if (cdevsw[sermajor].d_open == (void *)seropen)
990 break;
991
992
993 unit = CONUNIT; /* XXX: ick */
994
995 /*
996 * initialize required fields
997 */
998 cp->cn_dev = makedev(sermajor, unit);
999 if (serconsole == unit)
1000 cp->cn_pri = CN_REMOTE;
1001 else
1002 cp->cn_pri = CN_NORMAL;
1003 #ifdef KGDB
1004 if (major(kgdb_dev) == 1) /* XXX */
1005 kgdb_dev = makedev(sermajor, minor(kgdb_dev));
1006 #endif
1007 }
1008
1009 void
1010 sercninit(cp)
1011 struct consdev *cp;
1012 {
1013 int unit;
1014
1015 unit = SERUNIT(cp->cn_dev);
1016
1017 serinit(unit, serdefaultrate);
1018 serconsole = unit;
1019 serconsinit = 1;
1020 }
1021
1022 void
1023 serinit(unit, rate)
1024 int unit, rate;
1025 {
1026 int s;
1027
1028 s = splser();
1029 /*
1030 * might want to fiddle with the CIA later ???
1031 */
1032 custom.serper = (rate>=110 ? SERBRD(rate) : 0);
1033 splx(s);
1034 }
1035
1036 int
1037 sercngetc(dev)
1038 dev_t dev;
1039 {
1040 u_short stat;
1041 int c, s;
1042
1043 s = splser();
1044 /*
1045 * poll
1046 */
1047 while (((stat = custom.serdatr & 0xffff) & SERDATRF_RBF) == 0)
1048 ;
1049 c = stat & 0xff;
1050 /*
1051 * clear interrupt
1052 */
1053 custom.intreq = INTF_RBF;
1054 splx(s);
1055 return(c);
1056 }
1057
1058 /*
1059 * Console kernel output character routine.
1060 */
1061 void
1062 sercnputc(dev, c)
1063 dev_t dev;
1064 int c;
1065 {
1066 register int timo;
1067 int s;
1068
1069 s = splhigh();
1070
1071 if (serconsinit == 0) {
1072 (void)serinit(SERUNIT(dev), serdefaultrate);
1073 serconsinit = 1;
1074 }
1075
1076 /*
1077 * wait for any pending transmission to finish
1078 */
1079 timo = 50000;
1080 while (!(custom.serdatr & SERDATRF_TBE) && --timo);
1081
1082 /*
1083 * transmit char.
1084 */
1085 custom.serdat = (c & 0xff) | 0x100;
1086
1087 /*
1088 * wait for this transmission to complete
1089 */
1090 timo = 1500000;
1091 while (!(custom.serdatr & SERDATRF_TBE) && --timo)
1092 ;
1093
1094 /*
1095 * Wait for the device (my vt100..) to process the data, since we
1096 * don't do flow-control with cnputc
1097 */
1098 for (timo = 0; timo < 30000; timo++)
1099 ;
1100
1101 /*
1102 * clear any interrupts generated by this transmission
1103 */
1104 custom.intreq = INTF_TBE;
1105 splx(s);
1106 }
1107
1108 void
1109 sercnpollc(dev, on)
1110 dev_t dev;
1111 int on;
1112 {
1113 }
1114 #endif
1115