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