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