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