ser.c revision 1.43 1 /* $NetBSD: ser.c,v 1.43 1998/01/12 10:40:11 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * @(#)ser.c 7.12 (Berkeley) 6/27/91
36 */
37 /*
38 * XXX This file needs major cleanup it will never service more than one
39 * XXX unit.
40 */
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/ioctl.h>
45 #include <sys/device.h>
46 #include <sys/tty.h>
47 #include <sys/proc.h>
48 #include <sys/file.h>
49 #include <sys/malloc.h>
50 #include <sys/uio.h>
51 #include <sys/kernel.h>
52 #include <sys/syslog.h>
53 #include <sys/queue.h>
54 #include <machine/cpu.h>
55 #include <amiga/amiga/device.h>
56 #include <amiga/dev/serreg.h>
57 #include <amiga/amiga/custom.h>
58 #include <amiga/amiga/cia.h>
59 #include <amiga/amiga/cc.h>
60
61 #include <dev/cons.h>
62
63 #include <sys/conf.h>
64 #include <machine/conf.h>
65
66 #include "ser.h"
67 #if NSER > 0
68
69 void serattach __P((struct device *, struct device *, void *));
70 int sermatch __P((struct device *, struct cfdata *, 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 extern struct cfdriver ser_cd;
82
83 #ifndef SEROBUF_SIZE
84 #define SEROBUF_SIZE 32
85 #endif
86 #ifndef SERIBUF_SIZE
87 #define SERIBUF_SIZE 512
88 #endif
89
90 #define splser() spl5()
91
92 void serstart __P((struct tty *));
93 int serparam __P((struct tty *, struct termios *));
94 void serintr __P((int));
95 int serhwiflow __P((struct tty *, int));
96 int sermctl __P((dev_t dev, int, int));
97 void ser_fastint __P((void));
98 void sereint __P((int, int));
99 static void ser_putchar __P((struct tty *, u_short));
100 void ser_outintr __P((void));
101 void sercnprobe __P((struct consdev *));
102 void sercninit __P((struct consdev *));
103 void serinit __P((int, int));
104 int sercngetc __P((dev_t dev));
105 void sercnputc __P((dev_t, int));
106 void sercnpollc __P((dev_t, int));
107
108 int ser_active;
109 int ser_hasfifo;
110 int nser = NSER;
111 #ifdef SERCONSOLE
112 int serconsole = SERCONSOLE;
113 #else
114 int serconsole = -1;
115 #endif
116 int serconsinit;
117 int serdefaultrate = TTYDEF_SPEED;
118 int sermajor;
119 int serswflags;
120 #define SWFLAGS(dev) (serswflags | (DIALOUT(dev) ? TIOCFLAG_SOFTCAR : 0))
121
122 struct vbl_node ser_vbl_node[NSER];
123 struct tty ser_cons;
124 struct tty *ser_tty[NSER];
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 extern int ser_open_speed; /* current speed of open serial device */
155
156 #ifdef KGDB
157 #include <machine/remote-sl.h>
158
159 extern dev_t kgdb_dev;
160 extern int kgdb_rate;
161 extern int kgdb_debug_init;
162 #endif
163
164 #ifdef DEBUG
165 long fifoin[17];
166 long fifoout[17];
167 long serintrcount[16];
168 long sermintcount[16];
169 #endif
170
171 void sermint __P((register int unit));
172
173 int
174 sermatch(pdp, cfp, auxp)
175 struct device *pdp;
176 struct cfdata *cfp;
177 void *auxp;
178 {
179
180 if (matchname("ser", (char *)auxp) == 0 || cfp->cf_unit != 0)
181 return(0);
182 if (serconsole != 0 && amiga_realconfig == 0)
183 return(0);
184 return(1);
185 }
186
187
188 void
189 serattach(pdp, dp, auxp)
190 struct device *pdp, *dp;
191 void *auxp;
192 {
193 u_short ir;
194
195 ir = custom.intenar;
196 if (serconsole == 0)
197 DELAY(100000);
198
199 ser_active |= 1;
200 ser_vbl_node[0].function = (void (*) (void *)) sermint;
201 add_vbl_function(&ser_vbl_node[0], SER_VBL_PRIORITY, (void *) 0);
202 #ifdef KGDB
203 if (kgdb_dev == makedev(sermajor, 0)) {
204 if (serconsole == 0)
205 kgdb_dev = NODEV; /* can't debug over console port */
206 else {
207 (void) serinit(0, kgdb_rate);
208 serconsinit = 1; /* don't re-init in serputc */
209 if (kgdb_debug_init == 0)
210 printf(" kgdb enabled\n");
211 else {
212 /*
213 * Print prefix of device name,
214 * let kgdb_connect print the rest.
215 */
216 printf("ser0: ");
217 kgdb_connect(1);
218 }
219 }
220 }
221 #endif
222 /*
223 * Need to reset baud rate, etc. of next print so reset serconsinit.
224 */
225 if (0 == serconsole)
226 serconsinit = 0;
227 if (dp)
228 printf(": input fifo %d output fifo %d\n", SERIBUF_SIZE,
229 SEROBUF_SIZE);
230 }
231
232
233 /* ARGSUSED */
234 int
235 seropen(dev, flag, mode, p)
236 dev_t dev;
237 int flag, mode;
238 struct proc *p;
239 {
240 struct tty *tp;
241 int unit, error, s;
242
243 error = 0;
244 unit = SERUNIT(dev);
245
246 if (unit >= NSER || (ser_active & (1 << unit)) == 0)
247 return (ENXIO);
248
249 s = spltty();
250
251 if (ser_tty[unit])
252 tp = ser_tty[unit];
253 else {
254 tp = ((struct ser_softc *)ser_cd.cd_devs[unit])->ser_tty =
255 ser_tty[unit] = ttymalloc();
256 tty_attach(tp);
257 }
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 ser_open_speed = tp->t_ispeed;
332 return((*linesw[tp->t_line].l_open)(dev, tp));
333 }
334
335 /*ARGSUSED*/
336 int
337 serclose(dev, flag, mode, p)
338 dev_t dev;
339 int flag, mode;
340 struct proc *p;
341 {
342 struct tty *tp;
343 int unit;
344 int closebits;
345
346 unit = SERUNIT(dev);
347
348 tp = ser_tty[unit];
349 (*linesw[tp->t_line].l_close)(tp, flag);
350 custom.adkcon = ADKCONF_UARTBRK; /* clear break */
351 #ifdef KGDB
352 /*
353 * do not disable interrupts if debugging
354 */
355 if (dev != kgdb_dev)
356 #endif
357 custom.intena = INTF_RBF | INTF_TBE; /* disable interrups */
358 custom.intreq = INTF_RBF | INTF_TBE; /* clear intr request */
359
360 /*
361 * If HUPCL is not set, leave DTR unchanged.
362 */
363 if (tp->t_cflag & HUPCL)
364 closebits = 0;
365 else
366 closebits = sermctl(dev, 0, DMGET) & TIOCM_DTR;
367
368 (void) sermctl(dev, closebits, DMSET);
369
370 /*
371 * Idea from dev/isa/com.c:
372 * sleep a bit so that other side will notice, even if we reopen
373 * immediately.
374 */
375 (void) tsleep(tp, TTIPRI, ttclos, hz);
376 ttyclose(tp);
377 #if not_yet
378 if (tp != &ser_cons) {
379 remove_vbl_function(&ser_vbl_node[unit]);
380 ttyfree(tp);
381 ser_tty[unit] = (struct tty *) NULL;
382 }
383 #endif
384 ser_open_speed = tp->t_ispeed;
385 return (0);
386 }
387
388 int
389 serread(dev, uio, flag)
390 dev_t dev;
391 struct uio *uio;
392 int flag;
393 {
394 struct tty *tp;
395 if ((tp = ser_tty[SERUNIT(dev)]) == NULL)
396 return(ENXIO);
397 return((*linesw[tp->t_line].l_read)(tp, uio, flag));
398 }
399
400 int
401 serwrite(dev, uio, flag)
402 dev_t dev;
403 struct uio *uio;
404 int flag;
405 {
406 struct tty *tp;
407
408 if((tp = ser_tty[SERUNIT(dev)]) == NULL)
409 return(ENXIO);
410 return((*linesw[tp->t_line].l_write)(tp, uio, flag));
411 }
412
413 struct tty *
414 sertty(dev)
415 dev_t dev;
416 {
417 return (ser_tty[SERUNIT(dev)]);
418 }
419
420 /*
421 * We don't do any processing of data here, so we store the raw code
422 * obtained from the uart register. In theory, 110kBaud gives you
423 * 11kcps, so 16k buffer should be more than enough, interrupt
424 * latency of 1s should never happen, or something is seriously
425 * wrong..
426 */
427
428 static u_short serbuf[SERIBUF_SIZE];
429 static u_short *sbrpt = serbuf;
430 static u_short *sbwpt = serbuf;
431 static u_short sbcnt;
432 static u_short sbovfl;
433
434 /*
435 * This is a replacement for the lack of a hardware fifo. 32k should be
436 * enough (there's only one unit anyway, so this is not going to
437 * accumulate).
438 */
439 void
440 ser_fastint()
441 {
442 /*
443 * We're at RBE-level, which is higher than VBL-level which is used
444 * to periodically transmit contents of this buffer up one layer,
445 * so no spl-raising is necessary.
446 */
447 register u_short ints, code;
448
449 ints = custom.intreqr & INTF_RBF;
450 if (ints == 0)
451 return;
452
453 /*
454 * this register contains both data and status bits!
455 */
456 code = custom.serdatr;
457
458 /*
459 * clear interrupt
460 */
461 custom.intreq = ints;
462
463 /*
464 * check for buffer overflow.
465 */
466 if (sbcnt == SERIBUF_SIZE) {
467 ++sbovfl;
468 return;
469 }
470 /*
471 * store in buffer
472 */
473 *sbwpt++ = code;
474 if (sbwpt == serbuf + SERIBUF_SIZE)
475 sbwpt = serbuf;
476 ++sbcnt;
477 if (sbcnt > SERIBUF_SIZE - 20)
478 CLRRTS(ciab.pra); /* drop RTS if buffer almost full */
479 }
480
481
482 void
483 serintr(unit)
484 int unit;
485 {
486 int s1, s2, ovfl;
487 struct tty *tp = ser_tty[unit];
488
489 /*
490 * Make sure we're not interrupted by another
491 * vbl, but allow level5 ints
492 */
493 s1 = spltty();
494
495 /*
496 * pass along any acumulated information
497 */
498 while (sbcnt > 0 && (tp->t_state & TS_TBLOCK) == 0) {
499 /*
500 * no collision with ser_fastint()
501 */
502 sereint(unit, *sbrpt++);
503
504 ovfl = 0;
505 /* lock against ser_fastint() */
506 s2 = splser();
507 sbcnt--;
508 if (sbrpt == serbuf + SERIBUF_SIZE)
509 sbrpt = serbuf;
510 if (sbovfl != 0) {
511 ovfl = sbovfl;
512 sbovfl = 0;
513 }
514 splx(s2);
515 if (ovfl != 0)
516 log(LOG_WARNING, "ser0: %d ring buffer overflows.\n",
517 ovfl);
518 }
519 s2 = splser();
520 if (sbcnt == 0 && (tp->t_state & TS_TBLOCK) == 0)
521 SETRTS(ciab.pra); /* start accepting data again */
522 splx(s2);
523 splx(s1);
524 }
525
526 void
527 sereint(unit, stat)
528 int unit, stat;
529 {
530 struct tty *tp;
531 u_char ch;
532 int c;
533
534 tp = ser_tty[unit];
535 ch = stat & 0xff;
536 c = ch;
537
538 if ((tp->t_state & TS_ISOPEN) == 0) {
539 #ifdef KGDB
540 /* we don't care about parity errors */
541 if (kgdb_dev == makedev(sermajor, unit) && c == FRAME_END)
542 kgdb_connect(0); /* trap into kgdb */
543 #endif
544 return;
545 }
546
547 /*
548 * Check for break and (if enabled) parity error.
549 */
550 if ((stat & 0x1ff) == 0)
551 c |= TTY_FE;
552 else if ((tp->t_cflag & PARENB) &&
553 (((ch >> 7) + even_parity[ch & 0x7f]
554 + !!(tp->t_cflag & PARODD)) & 1))
555 c |= TTY_PE;
556
557 if (stat & SERDATRF_OVRUN)
558 log(LOG_WARNING, "ser0: silo overflow\n");
559
560 (*linesw[tp->t_line].l_rint)(c, tp);
561 }
562
563 /*
564 * This interrupt is periodically invoked in the vertical blank
565 * interrupt. It's used to keep track of the modem control lines
566 * and (new with the fast_int code) to move accumulated data
567 * up into the tty layer.
568 */
569 void
570 sermint(unit)
571 int unit;
572 {
573 struct tty *tp;
574 u_char stat, last, istat;
575
576 tp = ser_tty[unit];
577 if (!tp)
578 return;
579
580 if ((tp->t_state & (TS_ISOPEN | TS_WOPEN)) == 0) {
581 sbrpt = sbwpt = serbuf;
582 return;
583 }
584 /*
585 * empty buffer
586 */
587 serintr(unit);
588
589 stat = ciab.pra;
590 last = last_ciab_pra;
591 last_ciab_pra = stat;
592
593 /*
594 * check whether any interesting signal changed state
595 */
596 istat = stat ^ last;
597
598 if ((istat & CIAB_PRA_CD) &&
599 (SWFLAGS(tp->t_dev) & TIOCFLAG_SOFTCAR) == 0) {
600 if (ISDCD(stat))
601 (*linesw[tp->t_line].l_modem)(tp, 1);
602 else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
603 CLRDTR(stat);
604 CLRRTS(stat);
605 ciab.pra = stat;
606 last_ciab_pra = stat;
607 }
608 }
609 if ((istat & CIAB_PRA_CTS) && (tp->t_state & TS_ISOPEN) &&
610 (tp->t_cflag & CRTSCTS)) {
611 #if 0
612 /* the line is up and we want to do rts/cts flow control */
613 if (ISCTS(stat)) {
614 tp->t_state &= ~TS_TTSTOP;
615 ttstart(tp);
616 /* cause tbe-int if we were stuck there */
617 custom.intreq = INTF_SETCLR | INTF_TBE;
618 } else
619 tp->t_state |= TS_TTSTOP;
620 #else
621 /* do this on hardware level, not with tty driver */
622 if (ISCTS(stat)) {
623 tp->t_state &= ~TS_TTSTOP;
624 /* cause TBE interrupt */
625 custom.intreq = INTF_SETCLR | INTF_TBE;
626 }
627 #endif
628 }
629 }
630
631 int
632 serioctl(dev, cmd, data, flag, p)
633 dev_t dev;
634 u_long cmd;
635 caddr_t data;
636 int flag;
637 struct proc *p;
638 {
639 register struct tty *tp;
640 register int unit = SERUNIT(dev);
641 register int error;
642
643 tp = ser_tty[unit];
644 if (!tp)
645 return ENXIO;
646
647 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
648 if (error >= 0)
649 return(error);
650
651 error = ttioctl(tp, cmd, data, flag, p);
652 if (error >= 0)
653 return(error);
654
655 switch (cmd) {
656 case TIOCSBRK:
657 custom.adkcon = ADKCONF_SETCLR | ADKCONF_UARTBRK;
658 break;
659
660 case TIOCCBRK:
661 custom.adkcon = ADKCONF_UARTBRK;
662 break;
663
664 case TIOCSDTR:
665 (void) sermctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
666 break;
667
668 case TIOCCDTR:
669 (void) sermctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
670 break;
671
672 case TIOCMSET:
673 (void) sermctl(dev, *(int *) data, DMSET);
674 break;
675
676 case TIOCMBIS:
677 (void) sermctl(dev, *(int *) data, DMBIS);
678 break;
679
680 case TIOCMBIC:
681 (void) sermctl(dev, *(int *) data, DMBIC);
682 break;
683
684 case TIOCMGET:
685 *(int *)data = sermctl(dev, 0, DMGET);
686 break;
687 case TIOCGFLAGS:
688 *(int *)data = SWFLAGS(dev);
689 break;
690 case TIOCSFLAGS:
691 error = suser(p->p_ucred, &p->p_acflag);
692 if (error != 0)
693 return(EPERM);
694
695 serswflags = *(int *)data;
696 serswflags &= /* only allow valid flags */
697 (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
698 break;
699 default:
700 return(ENOTTY);
701 }
702
703 return(0);
704 }
705
706 int
707 serparam(tp, t)
708 struct tty *tp;
709 struct termios *t;
710 {
711 int cflag, unit, ospeed = 0;
712
713 cflag = t->c_cflag;
714 unit = SERUNIT(tp->t_dev);
715
716 if (t->c_ospeed > 0) {
717 if (t->c_ospeed < 110)
718 return(EINVAL);
719 ospeed = SERBRD(t->c_ospeed);
720 }
721
722 if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
723 return(EINVAL);
724
725 /*
726 * copy to tty
727 */
728 tp->t_ispeed = t->c_ispeed;
729 tp->t_ospeed = t->c_ospeed;
730 tp->t_cflag = cflag;
731 ser_open_speed = tp->t_ispeed;
732
733 /*
734 * enable interrupts
735 */
736 custom.intena = INTF_SETCLR | INTF_RBF | INTF_TBE;
737 last_ciab_pra = ciab.pra;
738
739 if (t->c_ospeed == 0)
740 (void)sermctl(tp->t_dev, 0, DMSET); /* hang up line */
741 else {
742 /*
743 * (re)enable DTR
744 * and set baud rate. (8 bit mode)
745 */
746 (void)sermctl(tp->t_dev, TIOCM_DTR | TIOCM_RTS, DMSET);
747 custom.serper = (0 << 15) | ospeed;
748 }
749 return(0);
750 }
751
752 int serhwiflow(tp, flag)
753 struct tty *tp;
754 int flag;
755 {
756 #if 0
757 printf ("serhwiflow %d\n", flag);
758 #endif
759 if (flag)
760 CLRRTS(ciab.pra);
761 else
762 SETRTS(ciab.pra);
763 return 1;
764 }
765
766 static void
767 ser_putchar(tp, c)
768 struct tty *tp;
769 u_short c;
770 {
771 if ((tp->t_cflag & CSIZE) == CS7 || (tp->t_cflag & PARENB))
772 c &= 0x7f;
773
774 /*
775 * handle parity if necessary
776 */
777 if (tp->t_cflag & PARENB) {
778 if (even_parity[c])
779 c |= 0x80;
780 if (tp->t_cflag & PARODD)
781 c ^= 0x80;
782 }
783 /*
784 * add stop bit(s)
785 */
786 if (tp->t_cflag & CSTOPB)
787 c |= 0x300;
788 else
789 c |= 0x100;
790
791 custom.serdat = c;
792 }
793
794
795 static u_char ser_outbuf[SEROBUF_SIZE];
796 static u_char *sob_ptr = ser_outbuf, *sob_end = ser_outbuf;
797
798 void
799 ser_outintr()
800 {
801 struct tty *tp = ser_tty[0];
802 int s;
803
804 tp = ser_tty[0];
805 s = spltty();
806
807 if (tp == 0)
808 goto out;
809
810 if ((custom.intreqr & INTF_TBE) == 0)
811 goto out;
812
813 /*
814 * clear interrupt
815 */
816 custom.intreq = INTF_TBE;
817
818 if (sob_ptr == sob_end) {
819 tp->t_state &= ~(TS_BUSY | TS_FLUSH);
820 if (tp->t_line)
821 (*linesw[tp->t_line].l_start)(tp);
822 else
823 serstart(tp);
824 goto out;
825 }
826
827 /*
828 * Do hardware flow control here. if the CTS line goes down, don't
829 * transmit anything. That way, we'll be restarted by the periodic
830 * interrupt when CTS comes back up.
831 */
832 if (ISCTS(ciab.pra))
833 ser_putchar(tp, *sob_ptr++);
834 else
835 CLRCTS(last_ciab_pra); /* Remember that CTS is off */
836 out:
837 splx(s);
838 }
839
840 void
841 serstart(tp)
842 struct tty *tp;
843 {
844 int cc, s, unit, hiwat;
845
846 hiwat = 0;
847
848 if ((tp->t_state & TS_ISOPEN) == 0)
849 return;
850
851 unit = SERUNIT(tp->t_dev);
852
853 s = spltty();
854 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
855 goto out;
856
857 cc = tp->t_outq.c_cc;
858 if (cc <= tp->t_lowat) {
859 if (tp->t_state & TS_ASLEEP) {
860 tp->t_state &= ~TS_ASLEEP;
861 wakeup((caddr_t) & tp->t_outq);
862 }
863 selwakeup(&tp->t_wsel);
864 }
865 if (cc == 0 || (tp->t_state & TS_BUSY))
866 goto out;
867
868 /*
869 * We only do bulk transfers if using CTSRTS flow control, not for
870 * (probably sloooow) ixon/ixoff devices.
871 */
872 if ((tp->t_cflag & CRTSCTS) == 0)
873 cc = 1;
874
875 /*
876 * Limit the amount of output we do in one burst
877 * to prevent hogging the CPU.
878 */
879 if (cc > SEROBUF_SIZE) {
880 hiwat++;
881 cc = SEROBUF_SIZE;
882 }
883 cc = q_to_b(&tp->t_outq, ser_outbuf, cc);
884 if (cc > 0) {
885 tp->t_state |= TS_BUSY;
886
887 sob_ptr = ser_outbuf;
888 sob_end = ser_outbuf + cc;
889
890 /*
891 * Get first character out, then have TBE-interrupts blow out
892 * further characters, until buffer is empty, and TS_BUSY gets
893 * cleared.
894 */
895 ser_putchar(tp, *sob_ptr++);
896 }
897 out:
898 splx(s);
899 }
900
901 /*
902 * Stop output on a line.
903 */
904 /*ARGSUSED*/
905 void
906 serstop(tp, flag)
907 struct tty *tp;
908 int flag;
909 {
910 int s;
911
912 s = spltty();
913 if (tp->t_state & TS_BUSY) {
914 if ((tp->t_state & TS_TTSTOP) == 0)
915 tp->t_state |= TS_FLUSH;
916 }
917 splx(s);
918 }
919
920 int
921 sermctl(dev, bits, how)
922 dev_t dev;
923 int bits, how;
924 {
925 int unit, s;
926 u_char ub = 0;
927
928 unit = SERUNIT(dev);
929
930 /*
931 * convert TIOCM* mask into CIA mask
932 * which is active low
933 */
934 if (how != DMGET) {
935 ub = 0;
936 if (bits & TIOCM_DTR)
937 ub |= CIAB_PRA_DTR;
938 if (bits & TIOCM_RTS)
939 ub |= CIAB_PRA_RTS;
940 if (bits & TIOCM_CTS)
941 ub |= CIAB_PRA_CTS;
942 if (bits & TIOCM_CD)
943 ub |= CIAB_PRA_CD;
944 if (bits & TIOCM_RI)
945 ub |= CIAB_PRA_SEL; /* collision with /dev/par ! */
946 if (bits & TIOCM_DSR)
947 ub |= CIAB_PRA_DSR;
948 }
949 s = spltty();
950 switch (how) {
951 case DMSET:
952 /* invert and set */
953 ciab.pra = ~ub;
954 break;
955
956 case DMBIC:
957 ciab.pra |= ub;
958 ub = ~ciab.pra;
959 break;
960
961 case DMBIS:
962 ciab.pra &= ~ub;
963 ub = ~ciab.pra;
964 break;
965
966 case DMGET:
967 ub = ~ciab.pra;
968 break;
969 }
970 (void)splx(s);
971
972 bits = 0;
973 if (ub & CIAB_PRA_DTR)
974 bits |= TIOCM_DTR;
975 if (ub & CIAB_PRA_RTS)
976 bits |= TIOCM_RTS;
977 if (ub & CIAB_PRA_CTS)
978 bits |= TIOCM_CTS;
979 if (ub & CIAB_PRA_CD)
980 bits |= TIOCM_CD;
981 if (ub & CIAB_PRA_SEL)
982 bits |= TIOCM_RI;
983 if (ub & CIAB_PRA_DSR)
984 bits |= TIOCM_DSR;
985
986 return(bits);
987 }
988
989 /*
990 * Following are all routines needed for SER to act as console
991 */
992 void
993 sercnprobe(cp)
994 struct consdev *cp;
995 {
996 int unit = CONUNIT;
997
998 /* locate the major number */
999 for (sermajor = 0; sermajor < nchrdev; sermajor++)
1000 if (cdevsw[sermajor].d_open == (void *)seropen)
1001 break;
1002
1003
1004 unit = CONUNIT; /* XXX: ick */
1005
1006 /*
1007 * initialize required fields
1008 */
1009 cp->cn_dev = makedev(sermajor, unit);
1010 if (serconsole == unit)
1011 cp->cn_pri = CN_REMOTE;
1012 else
1013 cp->cn_pri = CN_NORMAL;
1014 #ifdef KGDB
1015 if (major(kgdb_dev) == 1) /* XXX */
1016 kgdb_dev = makedev(sermajor, minor(kgdb_dev));
1017 #endif
1018 }
1019
1020 void
1021 sercninit(cp)
1022 struct consdev *cp;
1023 {
1024 int unit;
1025
1026 unit = SERUNIT(cp->cn_dev);
1027
1028 serinit(unit, serdefaultrate);
1029 serconsole = unit;
1030 serconsinit = 1;
1031 }
1032
1033 void
1034 serinit(unit, rate)
1035 int unit, rate;
1036 {
1037 int s;
1038
1039 s = splser();
1040 /*
1041 * might want to fiddle with the CIA later ???
1042 */
1043 custom.serper = (rate>=110 ? SERBRD(rate) : 0);
1044 splx(s);
1045 }
1046
1047 int
1048 sercngetc(dev)
1049 dev_t dev;
1050 {
1051 u_short stat;
1052 int c, s;
1053
1054 s = splser();
1055 /*
1056 * poll
1057 */
1058 while (((stat = custom.serdatr & 0xffff) & SERDATRF_RBF) == 0)
1059 ;
1060 c = stat & 0xff;
1061 /*
1062 * clear interrupt
1063 */
1064 custom.intreq = INTF_RBF;
1065 splx(s);
1066 return(c);
1067 }
1068
1069 /*
1070 * Console kernel output character routine.
1071 */
1072 void
1073 sercnputc(dev, c)
1074 dev_t dev;
1075 int c;
1076 {
1077 register int timo;
1078 int s;
1079
1080 s = splhigh();
1081
1082 if (serconsinit == 0) {
1083 (void)serinit(SERUNIT(dev), serdefaultrate);
1084 serconsinit = 1;
1085 }
1086
1087 /*
1088 * wait for any pending transmission to finish
1089 */
1090 timo = 50000;
1091 while (!(custom.serdatr & SERDATRF_TBE) && --timo);
1092
1093 /*
1094 * transmit char.
1095 */
1096 custom.serdat = (c & 0xff) | 0x100;
1097
1098 /*
1099 * wait for this transmission to complete
1100 */
1101 timo = 1500000;
1102 while (!(custom.serdatr & SERDATRF_TBE) && --timo)
1103 ;
1104
1105 /*
1106 * Wait for the device (my vt100..) to process the data, since we
1107 * don't do flow-control with cnputc
1108 */
1109 for (timo = 0; timo < 30000; timo++)
1110 ;
1111
1112 /*
1113 * clear any interrupts generated by this transmission
1114 */
1115 custom.intreq = INTF_TBE;
1116 splx(s);
1117 }
1118
1119 void
1120 sercnpollc(dev, on)
1121 dev_t dev;
1122 int on;
1123 {
1124 }
1125 #endif
1126