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