ser.c revision 1.41 1 /* $NetBSD: ser.c,v 1.41 1997/09/21 17:21:24 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 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, cfp, auxp)
175 struct device *pdp;
176 struct cfdata *cfp;
177 void *auxp;
178 {
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 int closebits;
344
345 unit = SERUNIT(dev);
346
347 tp = ser_tty[unit];
348 (*linesw[tp->t_line].l_close)(tp, flag);
349 custom.adkcon = ADKCONF_UARTBRK; /* clear break */
350 #ifdef KGDB
351 /*
352 * do not disable interrupts if debugging
353 */
354 if (dev != kgdb_dev)
355 #endif
356 custom.intena = INTF_RBF | INTF_TBE; /* disable interrups */
357 custom.intreq = INTF_RBF | INTF_TBE; /* clear intr request */
358
359 /*
360 * If HUPCL is not set, leave DTR unchanged.
361 */
362 if (tp->t_cflag & HUPCL)
363 closebits = 0;
364 else
365 closebits = sermctl(dev, 0, DMGET) & TIOCM_DTR;
366
367 (void) sermctl(dev, closebits, DMSET);
368
369 /*
370 * Idea from dev/isa/com.c:
371 * sleep a bit so that other side will notice, even if we reopen
372 * immediately.
373 */
374 (void) tsleep(tp, TTIPRI, ttclos, hz);
375 ttyclose(tp);
376 #if not_yet
377 if (tp != &ser_cons) {
378 remove_vbl_function(&ser_vbl_node[unit]);
379 ttyfree(tp);
380 ser_tty[unit] = (struct tty *) NULL;
381 }
382 #endif
383 return (0);
384 }
385
386 int
387 serread(dev, uio, flag)
388 dev_t dev;
389 struct uio *uio;
390 int flag;
391 {
392 struct tty *tp;
393 if ((tp = ser_tty[SERUNIT(dev)]) == NULL)
394 return(ENXIO);
395 return((*linesw[tp->t_line].l_read)(tp, uio, flag));
396 }
397
398 int
399 serwrite(dev, uio, flag)
400 dev_t dev;
401 struct uio *uio;
402 int flag;
403 {
404 struct tty *tp;
405
406 if((tp = ser_tty[SERUNIT(dev)]) == NULL)
407 return(ENXIO);
408 return((*linesw[tp->t_line].l_write)(tp, uio, flag));
409 }
410
411 struct tty *
412 sertty(dev)
413 dev_t dev;
414 {
415 return (ser_tty[SERUNIT(dev)]);
416 }
417
418 /*
419 * We don't do any processing of data here, so we store the raw code
420 * obtained from the uart register. In theory, 110kBaud gives you
421 * 11kcps, so 16k buffer should be more than enough, interrupt
422 * latency of 1s should never happen, or something is seriously
423 * wrong..
424 */
425
426 static u_short serbuf[SERIBUF_SIZE];
427 static u_short *sbrpt = serbuf;
428 static u_short *sbwpt = serbuf;
429 static u_short sbcnt;
430 static u_short sbovfl;
431
432 /*
433 * This is a replacement for the lack of a hardware fifo. 32k should be
434 * enough (there's only one unit anyway, so this is not going to
435 * accumulate).
436 */
437 void
438 ser_fastint()
439 {
440 /*
441 * We're at RBE-level, which is higher than VBL-level which is used
442 * to periodically transmit contents of this buffer up one layer,
443 * so no spl-raising is necessary.
444 */
445 register u_short ints, code;
446
447 ints = custom.intreqr & INTF_RBF;
448 if (ints == 0)
449 return;
450
451 /*
452 * this register contains both data and status bits!
453 */
454 code = custom.serdatr;
455
456 /*
457 * clear interrupt
458 */
459 custom.intreq = ints;
460
461 /*
462 * check for buffer overflow.
463 */
464 if (sbcnt == SERIBUF_SIZE) {
465 ++sbovfl;
466 return;
467 }
468 /*
469 * store in buffer
470 */
471 *sbwpt++ = code;
472 if (sbwpt == serbuf + SERIBUF_SIZE)
473 sbwpt = serbuf;
474 ++sbcnt;
475 if (sbcnt > SERIBUF_SIZE - 20)
476 CLRRTS(ciab.pra); /* drop RTS if buffer almost full */
477 }
478
479
480 void
481 serintr(unit)
482 int unit;
483 {
484 int s1, s2, ovfl;
485 struct tty *tp = ser_tty[unit];
486
487 /*
488 * Make sure we're not interrupted by another
489 * vbl, but allow level5 ints
490 */
491 s1 = spltty();
492
493 /*
494 * pass along any acumulated information
495 */
496 while (sbcnt > 0 && (tp->t_state & TS_TBLOCK) == 0) {
497 /*
498 * no collision with ser_fastint()
499 */
500 sereint(unit, *sbrpt++);
501
502 ovfl = 0;
503 /* lock against ser_fastint() */
504 s2 = splser();
505 sbcnt--;
506 if (sbrpt == serbuf + SERIBUF_SIZE)
507 sbrpt = serbuf;
508 if (sbovfl != 0) {
509 ovfl = sbovfl;
510 sbovfl = 0;
511 }
512 splx(s2);
513 if (ovfl != 0)
514 log(LOG_WARNING, "ser0: %d ring buffer overflows.\n",
515 ovfl);
516 }
517 s2 = splser();
518 if (sbcnt == 0 && (tp->t_state & TS_TBLOCK) == 0)
519 SETRTS(ciab.pra); /* start accepting data again */
520 splx(s2);
521 splx(s1);
522 }
523
524 void
525 sereint(unit, stat)
526 int unit, stat;
527 {
528 struct tty *tp;
529 u_char ch;
530 int c;
531
532 tp = ser_tty[unit];
533 ch = stat & 0xff;
534 c = ch;
535
536 if ((tp->t_state & TS_ISOPEN) == 0) {
537 #ifdef KGDB
538 /* we don't care about parity errors */
539 if (kgdb_dev == makedev(sermajor, unit) && c == FRAME_END)
540 kgdb_connect(0); /* trap into kgdb */
541 #endif
542 return;
543 }
544
545 /*
546 * Check for break and (if enabled) parity error.
547 */
548 if ((stat & 0x1ff) == 0)
549 c |= TTY_FE;
550 else if ((tp->t_cflag & PARENB) &&
551 (((ch >> 7) + even_parity[ch & 0x7f]
552 + !!(tp->t_cflag & PARODD)) & 1))
553 c |= TTY_PE;
554
555 if (stat & SERDATRF_OVRUN)
556 log(LOG_WARNING, "ser0: silo overflow\n");
557
558 (*linesw[tp->t_line].l_rint)(c, tp);
559 }
560
561 /*
562 * This interrupt is periodically invoked in the vertical blank
563 * interrupt. It's used to keep track of the modem control lines
564 * and (new with the fast_int code) to move accumulated data
565 * up into the tty layer.
566 */
567 void
568 sermint(unit)
569 int unit;
570 {
571 struct tty *tp;
572 u_char stat, last, istat;
573
574 tp = ser_tty[unit];
575 if (!tp)
576 return;
577
578 if ((tp->t_state & (TS_ISOPEN | TS_WOPEN)) == 0) {
579 sbrpt = sbwpt = serbuf;
580 return;
581 }
582 /*
583 * empty buffer
584 */
585 serintr(unit);
586
587 stat = ciab.pra;
588 last = last_ciab_pra;
589 last_ciab_pra = stat;
590
591 /*
592 * check whether any interesting signal changed state
593 */
594 istat = stat ^ last;
595
596 if ((istat & CIAB_PRA_CD) &&
597 (SWFLAGS(tp->t_dev) & TIOCFLAG_SOFTCAR) == 0) {
598 if (ISDCD(stat))
599 (*linesw[tp->t_line].l_modem)(tp, 1);
600 else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
601 CLRDTR(stat);
602 CLRRTS(stat);
603 ciab.pra = stat;
604 last_ciab_pra = stat;
605 }
606 }
607 if ((istat & CIAB_PRA_CTS) && (tp->t_state & TS_ISOPEN) &&
608 (tp->t_cflag & CRTSCTS)) {
609 #if 0
610 /* the line is up and we want to do rts/cts flow control */
611 if (ISCTS(stat)) {
612 tp->t_state &= ~TS_TTSTOP;
613 ttstart(tp);
614 /* cause tbe-int if we were stuck there */
615 custom.intreq = INTF_SETCLR | INTF_TBE;
616 } else
617 tp->t_state |= TS_TTSTOP;
618 #else
619 /* do this on hardware level, not with tty driver */
620 if (ISCTS(stat)) {
621 tp->t_state &= ~TS_TTSTOP;
622 /* cause TBE interrupt */
623 custom.intreq = INTF_SETCLR | INTF_TBE;
624 }
625 #endif
626 }
627 }
628
629 int
630 serioctl(dev, cmd, data, flag, p)
631 dev_t dev;
632 u_long cmd;
633 caddr_t data;
634 int flag;
635 struct proc *p;
636 {
637 register struct tty *tp;
638 register int unit = SERUNIT(dev);
639 register int error;
640
641 tp = ser_tty[unit];
642 if (!tp)
643 return ENXIO;
644
645 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
646 if (error >= 0)
647 return(error);
648
649 error = ttioctl(tp, cmd, data, flag, p);
650 if (error >= 0)
651 return(error);
652
653 switch (cmd) {
654 case TIOCSBRK:
655 custom.adkcon = ADKCONF_SETCLR | ADKCONF_UARTBRK;
656 break;
657
658 case TIOCCBRK:
659 custom.adkcon = ADKCONF_UARTBRK;
660 break;
661
662 case TIOCSDTR:
663 (void) sermctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
664 break;
665
666 case TIOCCDTR:
667 (void) sermctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
668 break;
669
670 case TIOCMSET:
671 (void) sermctl(dev, *(int *) data, DMSET);
672 break;
673
674 case TIOCMBIS:
675 (void) sermctl(dev, *(int *) data, DMBIS);
676 break;
677
678 case TIOCMBIC:
679 (void) sermctl(dev, *(int *) data, DMBIC);
680 break;
681
682 case TIOCMGET:
683 *(int *)data = sermctl(dev, 0, DMGET);
684 break;
685 case TIOCGFLAGS:
686 *(int *)data = SWFLAGS(dev);
687 break;
688 case TIOCSFLAGS:
689 error = suser(p->p_ucred, &p->p_acflag);
690 if (error != 0)
691 return(EPERM);
692
693 serswflags = *(int *)data;
694 serswflags &= /* only allow valid flags */
695 (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
696 break;
697 default:
698 return(ENOTTY);
699 }
700
701 return(0);
702 }
703
704 int
705 serparam(tp, t)
706 struct tty *tp;
707 struct termios *t;
708 {
709 int cflag, unit, ospeed = 0;
710
711 cflag = t->c_cflag;
712 unit = SERUNIT(tp->t_dev);
713
714 if (t->c_ospeed > 0) {
715 if (t->c_ospeed < 110)
716 return(EINVAL);
717 ospeed = SERBRD(t->c_ospeed);
718 }
719
720 if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
721 return(EINVAL);
722
723 /*
724 * copy to tty
725 */
726 tp->t_ispeed = t->c_ispeed;
727 tp->t_ospeed = t->c_ospeed;
728 tp->t_cflag = cflag;
729
730 /*
731 * enable interrupts
732 */
733 custom.intena = INTF_SETCLR | INTF_RBF | INTF_TBE;
734 last_ciab_pra = ciab.pra;
735
736 if (t->c_ospeed == 0)
737 (void)sermctl(tp->t_dev, 0, DMSET); /* hang up line */
738 else {
739 /*
740 * (re)enable DTR
741 * and set baud rate. (8 bit mode)
742 */
743 (void)sermctl(tp->t_dev, TIOCM_DTR | TIOCM_RTS, DMSET);
744 custom.serper = (0 << 15) | ospeed;
745 }
746 return(0);
747 }
748
749 int serhwiflow(tp, flag)
750 struct tty *tp;
751 int flag;
752 {
753 #if 0
754 printf ("serhwiflow %d\n", flag);
755 #endif
756 if (flag)
757 CLRRTS(ciab.pra);
758 else
759 SETRTS(ciab.pra);
760 return 1;
761 }
762
763 static void
764 ser_putchar(tp, c)
765 struct tty *tp;
766 u_short c;
767 {
768 if ((tp->t_cflag & CSIZE) == CS7 || (tp->t_cflag & PARENB))
769 c &= 0x7f;
770
771 /*
772 * handle parity if necessary
773 */
774 if (tp->t_cflag & PARENB) {
775 if (even_parity[c])
776 c |= 0x80;
777 if (tp->t_cflag & PARODD)
778 c ^= 0x80;
779 }
780 /*
781 * add stop bit(s)
782 */
783 if (tp->t_cflag & CSTOPB)
784 c |= 0x300;
785 else
786 c |= 0x100;
787
788 custom.serdat = c;
789 }
790
791
792 static u_char ser_outbuf[SEROBUF_SIZE];
793 static u_char *sob_ptr = ser_outbuf, *sob_end = ser_outbuf;
794
795 void
796 ser_outintr()
797 {
798 struct tty *tp = ser_tty[0];
799 int s;
800
801 tp = ser_tty[0];
802 s = spltty();
803
804 if (tp == 0)
805 goto out;
806
807 if ((custom.intreqr & INTF_TBE) == 0)
808 goto out;
809
810 /*
811 * clear interrupt
812 */
813 custom.intreq = INTF_TBE;
814
815 if (sob_ptr == sob_end) {
816 tp->t_state &= ~(TS_BUSY | TS_FLUSH);
817 if (tp->t_line)
818 (*linesw[tp->t_line].l_start)(tp);
819 else
820 serstart(tp);
821 goto out;
822 }
823
824 /*
825 * Do hardware flow control here. if the CTS line goes down, don't
826 * transmit anything. That way, we'll be restarted by the periodic
827 * interrupt when CTS comes back up.
828 */
829 if (ISCTS(ciab.pra))
830 ser_putchar(tp, *sob_ptr++);
831 else
832 CLRCTS(last_ciab_pra); /* Remember that CTS is off */
833 out:
834 splx(s);
835 }
836
837 void
838 serstart(tp)
839 struct tty *tp;
840 {
841 int cc, s, unit, hiwat;
842
843 hiwat = 0;
844
845 if ((tp->t_state & TS_ISOPEN) == 0)
846 return;
847
848 unit = SERUNIT(tp->t_dev);
849
850 s = spltty();
851 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
852 goto out;
853
854 cc = tp->t_outq.c_cc;
855 if (cc <= tp->t_lowat) {
856 if (tp->t_state & TS_ASLEEP) {
857 tp->t_state &= ~TS_ASLEEP;
858 wakeup((caddr_t) & tp->t_outq);
859 }
860 selwakeup(&tp->t_wsel);
861 }
862 if (cc == 0 || (tp->t_state & TS_BUSY))
863 goto out;
864
865 /*
866 * We only do bulk transfers if using CTSRTS flow control, not for
867 * (probably sloooow) ixon/ixoff devices.
868 */
869 if ((tp->t_cflag & CRTSCTS) == 0)
870 cc = 1;
871
872 /*
873 * Limit the amount of output we do in one burst
874 * to prevent hogging the CPU.
875 */
876 if (cc > SEROBUF_SIZE) {
877 hiwat++;
878 cc = SEROBUF_SIZE;
879 }
880 cc = q_to_b(&tp->t_outq, ser_outbuf, cc);
881 if (cc > 0) {
882 tp->t_state |= TS_BUSY;
883
884 sob_ptr = ser_outbuf;
885 sob_end = ser_outbuf + cc;
886
887 /*
888 * Get first character out, then have TBE-interrupts blow out
889 * further characters, until buffer is empty, and TS_BUSY gets
890 * cleared.
891 */
892 ser_putchar(tp, *sob_ptr++);
893 }
894 out:
895 splx(s);
896 }
897
898 /*
899 * Stop output on a line.
900 */
901 /*ARGSUSED*/
902 void
903 serstop(tp, flag)
904 struct tty *tp;
905 int flag;
906 {
907 int s;
908
909 s = spltty();
910 if (tp->t_state & TS_BUSY) {
911 if ((tp->t_state & TS_TTSTOP) == 0)
912 tp->t_state |= TS_FLUSH;
913 }
914 splx(s);
915 }
916
917 int
918 sermctl(dev, bits, how)
919 dev_t dev;
920 int bits, how;
921 {
922 int unit, s;
923 u_char ub = 0;
924
925 unit = SERUNIT(dev);
926
927 /*
928 * convert TIOCM* mask into CIA mask
929 * which is active low
930 */
931 if (how != DMGET) {
932 ub = 0;
933 if (bits & TIOCM_DTR)
934 ub |= CIAB_PRA_DTR;
935 if (bits & TIOCM_RTS)
936 ub |= CIAB_PRA_RTS;
937 if (bits & TIOCM_CTS)
938 ub |= CIAB_PRA_CTS;
939 if (bits & TIOCM_CD)
940 ub |= CIAB_PRA_CD;
941 if (bits & TIOCM_RI)
942 ub |= CIAB_PRA_SEL; /* collision with /dev/par ! */
943 if (bits & TIOCM_DSR)
944 ub |= CIAB_PRA_DSR;
945 }
946 s = spltty();
947 switch (how) {
948 case DMSET:
949 /* invert and set */
950 ciab.pra = ~ub;
951 break;
952
953 case DMBIC:
954 ciab.pra |= ub;
955 ub = ~ciab.pra;
956 break;
957
958 case DMBIS:
959 ciab.pra &= ~ub;
960 ub = ~ciab.pra;
961 break;
962
963 case DMGET:
964 ub = ~ciab.pra;
965 break;
966 }
967 (void)splx(s);
968
969 bits = 0;
970 if (ub & CIAB_PRA_DTR)
971 bits |= TIOCM_DTR;
972 if (ub & CIAB_PRA_RTS)
973 bits |= TIOCM_RTS;
974 if (ub & CIAB_PRA_CTS)
975 bits |= TIOCM_CTS;
976 if (ub & CIAB_PRA_CD)
977 bits |= TIOCM_CD;
978 if (ub & CIAB_PRA_SEL)
979 bits |= TIOCM_RI;
980 if (ub & CIAB_PRA_DSR)
981 bits |= TIOCM_DSR;
982
983 return(bits);
984 }
985
986 /*
987 * Following are all routines needed for SER to act as console
988 */
989 void
990 sercnprobe(cp)
991 struct consdev *cp;
992 {
993 int unit = CONUNIT;
994
995 /* locate the major number */
996 for (sermajor = 0; sermajor < nchrdev; sermajor++)
997 if (cdevsw[sermajor].d_open == (void *)seropen)
998 break;
999
1000
1001 unit = CONUNIT; /* XXX: ick */
1002
1003 /*
1004 * initialize required fields
1005 */
1006 cp->cn_dev = makedev(sermajor, unit);
1007 if (serconsole == unit)
1008 cp->cn_pri = CN_REMOTE;
1009 else
1010 cp->cn_pri = CN_NORMAL;
1011 #ifdef KGDB
1012 if (major(kgdb_dev) == 1) /* XXX */
1013 kgdb_dev = makedev(sermajor, minor(kgdb_dev));
1014 #endif
1015 }
1016
1017 void
1018 sercninit(cp)
1019 struct consdev *cp;
1020 {
1021 int unit;
1022
1023 unit = SERUNIT(cp->cn_dev);
1024
1025 serinit(unit, serdefaultrate);
1026 serconsole = unit;
1027 serconsinit = 1;
1028 }
1029
1030 void
1031 serinit(unit, rate)
1032 int unit, rate;
1033 {
1034 int s;
1035
1036 s = splser();
1037 /*
1038 * might want to fiddle with the CIA later ???
1039 */
1040 custom.serper = (rate>=110 ? SERBRD(rate) : 0);
1041 splx(s);
1042 }
1043
1044 int
1045 sercngetc(dev)
1046 dev_t dev;
1047 {
1048 u_short stat;
1049 int c, s;
1050
1051 s = splser();
1052 /*
1053 * poll
1054 */
1055 while (((stat = custom.serdatr & 0xffff) & SERDATRF_RBF) == 0)
1056 ;
1057 c = stat & 0xff;
1058 /*
1059 * clear interrupt
1060 */
1061 custom.intreq = INTF_RBF;
1062 splx(s);
1063 return(c);
1064 }
1065
1066 /*
1067 * Console kernel output character routine.
1068 */
1069 void
1070 sercnputc(dev, c)
1071 dev_t dev;
1072 int c;
1073 {
1074 register int timo;
1075 int s;
1076
1077 s = splhigh();
1078
1079 if (serconsinit == 0) {
1080 (void)serinit(SERUNIT(dev), serdefaultrate);
1081 serconsinit = 1;
1082 }
1083
1084 /*
1085 * wait for any pending transmission to finish
1086 */
1087 timo = 50000;
1088 while (!(custom.serdatr & SERDATRF_TBE) && --timo);
1089
1090 /*
1091 * transmit char.
1092 */
1093 custom.serdat = (c & 0xff) | 0x100;
1094
1095 /*
1096 * wait for this transmission to complete
1097 */
1098 timo = 1500000;
1099 while (!(custom.serdatr & SERDATRF_TBE) && --timo)
1100 ;
1101
1102 /*
1103 * Wait for the device (my vt100..) to process the data, since we
1104 * don't do flow-control with cnputc
1105 */
1106 for (timo = 0; timo < 30000; timo++)
1107 ;
1108
1109 /*
1110 * clear any interrupts generated by this transmission
1111 */
1112 custom.intreq = INTF_TBE;
1113 splx(s);
1114 }
1115
1116 void
1117 sercnpollc(dev, on)
1118 dev_t dev;
1119 int on;
1120 {
1121 }
1122 #endif
1123