ser.c revision 1.32 1 /* $NetBSD: ser.c,v 1.32 1996/04/23 16:38:32 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 if (sbcnt == 0 && (tp->t_state & TS_TBLOCK) == 0)
508 SETRTS(ciab.pra); /* start accepting data again */
509 splx(s1);
510 }
511
512 void
513 sereint(unit, stat)
514 int unit, stat;
515 {
516 struct tty *tp;
517 u_char ch;
518 int c;
519
520 tp = ser_tty[unit];
521 ch = stat & 0xff;
522 c = ch;
523
524 if ((tp->t_state & TS_ISOPEN) == 0) {
525 #ifdef KGDB
526 /* we don't care about parity errors */
527 if (kgdb_dev == makedev(sermajor, unit) && c == FRAME_END)
528 kgdb_connect(0); /* trap into kgdb */
529 #endif
530 return;
531 }
532
533 /*
534 * Check for break and (if enabled) parity error.
535 */
536 if ((stat & 0x1ff) == 0)
537 c |= TTY_FE;
538 else if ((tp->t_cflag & PARENB) &&
539 (((ch >> 7) + even_parity[ch & 0x7f]
540 + !!(tp->t_cflag & PARODD)) & 1))
541 c |= TTY_PE;
542
543 if (stat & SERDATRF_OVRUN)
544 log(LOG_WARNING, "ser0: silo overflow\n");
545
546 (*linesw[tp->t_line].l_rint)(c, tp);
547 }
548
549 /*
550 * This interrupt is periodically invoked in the vertical blank
551 * interrupt. It's used to keep track of the modem control lines
552 * and (new with the fast_int code) to move accumulated data
553 * up into the tty layer.
554 */
555 void
556 sermint(unit)
557 int unit;
558 {
559 struct tty *tp;
560 u_char stat, last, istat;
561
562 tp = ser_tty[unit];
563 if (!tp)
564 return;
565
566 if ((tp->t_state & (TS_ISOPEN | TS_WOPEN)) == 0) {
567 sbrpt = sbwpt = serbuf;
568 return;
569 }
570 /*
571 * empty buffer
572 */
573 serintr(unit);
574
575 stat = ciab.pra;
576 last = last_ciab_pra;
577 last_ciab_pra = stat;
578
579 /*
580 * check whether any interesting signal changed state
581 */
582 istat = stat ^ last;
583
584 if ((istat & CIAB_PRA_CD) &&
585 (SWFLAGS(tp->t_dev) & TIOCFLAG_SOFTCAR) == 0) {
586 if (ISDCD(stat))
587 (*linesw[tp->t_line].l_modem)(tp, 1);
588 else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
589 CLRDTR(stat);
590 CLRRTS(stat);
591 ciab.pra = stat;
592 last_ciab_pra = stat;
593 }
594 }
595 if ((istat & CIAB_PRA_CTS) && (tp->t_state & TS_ISOPEN) &&
596 (tp->t_cflag & CRTSCTS)) {
597 #if 0
598 /* the line is up and we want to do rts/cts flow control */
599 if (ISCTS(stat)) {
600 tp->t_state &= ~TS_TTSTOP;
601 ttstart(tp);
602 /* cause tbe-int if we were stuck there */
603 custom.intreq = INTF_SETCLR | INTF_TBE;
604 } else
605 tp->t_state |= TS_TTSTOP;
606 #else
607 /* do this on hardware level, not with tty driver */
608 if (ISCTS(stat)) {
609 tp->t_state &= ~TS_TTSTOP;
610 /* cause TBE interrupt */
611 custom.intreq = INTF_SETCLR | INTF_TBE;
612 }
613 #endif
614 }
615 }
616
617 int
618 serioctl(dev, cmd, data, flag, p)
619 dev_t dev;
620 u_long cmd;
621 caddr_t data;
622 int flag;
623 struct proc *p;
624 {
625 register struct tty *tp;
626 register int unit = SERUNIT(dev);
627 register int error;
628
629 tp = ser_tty[unit];
630 if (!tp)
631 return ENXIO;
632
633 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
634 if (error >= 0)
635 return(error);
636
637 error = ttioctl(tp, cmd, data, flag, p);
638 if (error >= 0)
639 return(error);
640
641 switch (cmd) {
642 case TIOCSBRK:
643 custom.adkcon = ADKCONF_SETCLR | ADKCONF_UARTBRK;
644 break;
645
646 case TIOCCBRK:
647 custom.adkcon = ADKCONF_UARTBRK;
648 break;
649
650 case TIOCSDTR:
651 (void) sermctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
652 break;
653
654 case TIOCCDTR:
655 (void) sermctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
656 break;
657
658 case TIOCMSET:
659 (void) sermctl(dev, *(int *) data, DMSET);
660 break;
661
662 case TIOCMBIS:
663 (void) sermctl(dev, *(int *) data, DMBIS);
664 break;
665
666 case TIOCMBIC:
667 (void) sermctl(dev, *(int *) data, DMBIC);
668 break;
669
670 case TIOCMGET:
671 *(int *)data = sermctl(dev, 0, DMGET);
672 break;
673 case TIOCGFLAGS:
674 *(int *)data = SWFLAGS(dev);
675 break;
676 case TIOCSFLAGS:
677 error = suser(p->p_ucred, &p->p_acflag);
678 if (error != 0)
679 return(EPERM);
680
681 serswflags = *(int *)data;
682 serswflags &= /* only allow valid flags */
683 (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
684 break;
685 default:
686 return(ENOTTY);
687 }
688
689 return(0);
690 }
691
692 int
693 serparam(tp, t)
694 struct tty *tp;
695 struct termios *t;
696 {
697 int cflag, unit, ospeed;
698
699 cflag = t->c_cflag;
700 unit = SERUNIT(tp->t_dev);
701
702 if (t->c_ospeed > 0) {
703 if (t->c_ospeed < 110)
704 return(EINVAL);
705 ospeed = SERBRD(t->c_ospeed);
706 }
707
708 if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
709 return(EINVAL);
710
711 /*
712 * copy to tty
713 */
714 tp->t_ispeed = t->c_ispeed;
715 tp->t_ospeed = t->c_ospeed;
716 tp->t_cflag = cflag;
717
718 /*
719 * enable interrupts
720 */
721 custom.intena = INTF_SETCLR | INTF_RBF | INTF_TBE;
722 last_ciab_pra = ciab.pra;
723
724 if (t->c_ospeed == 0)
725 (void)sermctl(tp->t_dev, 0, DMSET); /* hang up line */
726 else {
727 /*
728 * (re)enable DTR
729 * and set baud rate. (8 bit mode)
730 */
731 (void)sermctl(tp->t_dev, TIOCM_DTR | TIOCM_RTS, DMSET);
732 custom.serper = (0 << 15) | ospeed;
733 }
734 return(0);
735 }
736
737 int serhwiflow(tp, flag)
738 struct tty *tp;
739 int flag;
740 {
741 #if 0
742 printf ("serhwiflow %d\n", flag);
743 #endif
744 if (flag)
745 CLRRTS(ciab.pra);
746 else
747 SETRTS(ciab.pra);
748 return 1;
749 }
750
751 static void
752 ser_putchar(tp, c)
753 struct tty *tp;
754 u_short c;
755 {
756 if ((tp->t_cflag & CSIZE) == CS7 || (tp->t_cflag & PARENB))
757 c &= 0x7f;
758
759 /*
760 * handle parity if necessary
761 */
762 if (tp->t_cflag & PARENB) {
763 if (even_parity[c])
764 c |= 0x80;
765 if (tp->t_cflag & PARODD)
766 c ^= 0x80;
767 }
768 /*
769 * add stop bit(s)
770 */
771 if (tp->t_cflag & CSTOPB)
772 c |= 0x300;
773 else
774 c |= 0x100;
775
776 custom.serdat = c;
777 }
778
779
780 static u_char ser_outbuf[SEROBUF_SIZE];
781 static u_char *sob_ptr = ser_outbuf, *sob_end = ser_outbuf;
782
783 void
784 ser_outintr()
785 {
786 struct tty *tp = ser_tty[0];
787 int s;
788
789 tp = ser_tty[0];
790 s = spltty();
791
792 if (tp == 0)
793 goto out;
794
795 if ((custom.intreqr & INTF_TBE) == 0)
796 goto out;
797
798 /*
799 * clear interrupt
800 */
801 custom.intreq = INTF_TBE;
802
803 if (sob_ptr == sob_end) {
804 tp->t_state &= ~(TS_BUSY | TS_FLUSH);
805 if (tp->t_line)
806 (*linesw[tp->t_line].l_start)(tp);
807 else
808 serstart(tp);
809 goto out;
810 }
811
812 /*
813 * Do hardware flow control here. if the CTS line goes down, don't
814 * transmit anything. That way, we'll be restarted by the periodic
815 * interrupt when CTS comes back up.
816 */
817 if (ISCTS(ciab.pra))
818 ser_putchar(tp, *sob_ptr++);
819 else
820 CLRCTS(last_ciab_pra); /* Remember that CTS is off */
821 out:
822 splx(s);
823 }
824
825 void
826 serstart(tp)
827 struct tty *tp;
828 {
829 int cc, s, unit, hiwat;
830
831 hiwat = 0;
832
833 if ((tp->t_state & TS_ISOPEN) == 0)
834 return;
835
836 unit = SERUNIT(tp->t_dev);
837
838 s = spltty();
839 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
840 goto out;
841
842 cc = tp->t_outq.c_cc;
843 if (cc <= tp->t_lowat) {
844 if (tp->t_state & TS_ASLEEP) {
845 tp->t_state &= ~TS_ASLEEP;
846 wakeup((caddr_t) & tp->t_outq);
847 }
848 selwakeup(&tp->t_wsel);
849 }
850 if (cc == 0 || (tp->t_state & TS_BUSY))
851 goto out;
852
853 /*
854 * We only do bulk transfers if using CTSRTS flow control, not for
855 * (probably sloooow) ixon/ixoff devices.
856 */
857 if ((tp->t_cflag & CRTSCTS) == 0)
858 cc = 1;
859
860 /*
861 * Limit the amount of output we do in one burst
862 * to prevent hogging the CPU.
863 */
864 if (cc > SEROBUF_SIZE) {
865 hiwat++;
866 cc = SEROBUF_SIZE;
867 }
868 cc = q_to_b(&tp->t_outq, ser_outbuf, cc);
869 if (cc > 0) {
870 tp->t_state |= TS_BUSY;
871
872 sob_ptr = ser_outbuf;
873 sob_end = ser_outbuf + cc;
874
875 /*
876 * Get first character out, then have TBE-interrupts blow out
877 * further characters, until buffer is empty, and TS_BUSY gets
878 * cleared.
879 */
880 ser_putchar(tp, *sob_ptr++);
881 }
882 out:
883 splx(s);
884 }
885
886 /*
887 * Stop output on a line.
888 */
889 /*ARGSUSED*/
890 int
891 serstop(tp, flag)
892 struct tty *tp;
893 int flag;
894 {
895 int s;
896
897 s = spltty();
898 if (tp->t_state & TS_BUSY) {
899 if ((tp->t_state & TS_TTSTOP) == 0)
900 tp->t_state |= TS_FLUSH;
901 }
902 splx(s);
903 return 0;
904 }
905
906 int
907 sermctl(dev, bits, how)
908 dev_t dev;
909 int bits, how;
910 {
911 int unit, s;
912 u_char ub = 0;
913
914 unit = SERUNIT(dev);
915
916 /*
917 * convert TIOCM* mask into CIA mask
918 * which is active low
919 */
920 if (how != DMGET) {
921 ub = 0;
922 if (bits & TIOCM_DTR)
923 ub |= CIAB_PRA_DTR;
924 if (bits & TIOCM_RTS)
925 ub |= CIAB_PRA_RTS;
926 if (bits & TIOCM_CTS)
927 ub |= CIAB_PRA_CTS;
928 if (bits & TIOCM_CD)
929 ub |= CIAB_PRA_CD;
930 if (bits & TIOCM_RI)
931 ub |= CIAB_PRA_SEL; /* collision with /dev/par ! */
932 if (bits & TIOCM_DSR)
933 ub |= CIAB_PRA_DSR;
934 }
935 s = spltty();
936 switch (how) {
937 case DMSET:
938 /* invert and set */
939 ciab.pra = ~ub;
940 break;
941
942 case DMBIC:
943 ciab.pra |= ub;
944 ub = ~ciab.pra;
945 break;
946
947 case DMBIS:
948 ciab.pra &= ~ub;
949 ub = ~ciab.pra;
950 break;
951
952 case DMGET:
953 ub = ~ciab.pra;
954 break;
955 }
956 (void)splx(s);
957
958 bits = 0;
959 if (ub & CIAB_PRA_DTR)
960 bits |= TIOCM_DTR;
961 if (ub & CIAB_PRA_RTS)
962 bits |= TIOCM_RTS;
963 if (ub & CIAB_PRA_CTS)
964 bits |= TIOCM_CTS;
965 if (ub & CIAB_PRA_CD)
966 bits |= TIOCM_CD;
967 if (ub & CIAB_PRA_SEL)
968 bits |= TIOCM_RI;
969 if (ub & CIAB_PRA_DSR)
970 bits |= TIOCM_DSR;
971
972 return(bits);
973 }
974
975 /*
976 * Following are all routines needed for SER to act as console
977 */
978 void
979 sercnprobe(cp)
980 struct consdev *cp;
981 {
982 int unit = CONUNIT;
983
984 /* locate the major number */
985 for (sermajor = 0; sermajor < nchrdev; sermajor++)
986 if (cdevsw[sermajor].d_open == (void *)seropen)
987 break;
988
989
990 unit = CONUNIT; /* XXX: ick */
991
992 /*
993 * initialize required fields
994 */
995 cp->cn_dev = makedev(sermajor, unit);
996 if (serconsole == unit)
997 cp->cn_pri = CN_REMOTE;
998 else
999 cp->cn_pri = CN_NORMAL;
1000 #ifdef KGDB
1001 if (major(kgdb_dev) == 1) /* XXX */
1002 kgdb_dev = makedev(sermajor, minor(kgdb_dev));
1003 #endif
1004 }
1005
1006 void
1007 sercninit(cp)
1008 struct consdev *cp;
1009 {
1010 int unit;
1011
1012 unit = SERUNIT(cp->cn_dev);
1013
1014 serinit(unit, serdefaultrate);
1015 serconsole = unit;
1016 serconsinit = 1;
1017 }
1018
1019 void
1020 serinit(unit, rate)
1021 int unit, rate;
1022 {
1023 int s;
1024
1025 s = splser();
1026 /*
1027 * might want to fiddle with the CIA later ???
1028 */
1029 custom.serper = (rate>=110 ? SERBRD(rate) : 0);
1030 splx(s);
1031 }
1032
1033 int
1034 sercngetc(dev)
1035 dev_t dev;
1036 {
1037 u_short stat;
1038 int c, s;
1039
1040 s = splser();
1041 /*
1042 * poll
1043 */
1044 while (((stat = custom.serdatr & 0xffff) & SERDATRF_RBF) == 0)
1045 ;
1046 c = stat & 0xff;
1047 /*
1048 * clear interrupt
1049 */
1050 custom.intreq = INTF_RBF;
1051 splx(s);
1052 return(c);
1053 }
1054
1055 /*
1056 * Console kernel output character routine.
1057 */
1058 void
1059 sercnputc(dev, c)
1060 dev_t dev;
1061 int c;
1062 {
1063 register int timo;
1064 int s;
1065
1066 s = splhigh();
1067
1068 if (serconsinit == 0) {
1069 (void)serinit(SERUNIT(dev), serdefaultrate);
1070 serconsinit = 1;
1071 }
1072
1073 /*
1074 * wait for any pending transmission to finish
1075 */
1076 timo = 50000;
1077 while (!(custom.serdatr & SERDATRF_TBE) && --timo);
1078
1079 /*
1080 * transmit char.
1081 */
1082 custom.serdat = (c & 0xff) | 0x100;
1083
1084 /*
1085 * wait for this transmission to complete
1086 */
1087 timo = 1500000;
1088 while (!(custom.serdatr & SERDATRF_TBE) && --timo)
1089 ;
1090
1091 /*
1092 * Wait for the device (my vt100..) to process the data, since we
1093 * don't do flow-control with cnputc
1094 */
1095 for (timo = 0; timo < 30000; timo++)
1096 ;
1097
1098 /*
1099 * clear any interrupts generated by this transmission
1100 */
1101 custom.intreq = INTF_TBE;
1102 splx(s);
1103 }
1104
1105 void
1106 sercnpollc(dev, on)
1107 dev_t dev;
1108 int on;
1109 {
1110 }
1111 #endif
1112