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