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