ser.c revision 1.23 1 /* $NetBSD: ser.c,v 1.23 1994/10/26 02:04:51 cgd 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", 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];
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] = 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 caddr_t data;
605 struct proc *p;
606 {
607 register struct tty *tp;
608 register int unit = SERUNIT(dev);
609 register int error;
610
611 tp = ser_tty[unit];
612 if (!tp)
613 return ENXIO;
614
615 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
616 if (error >= 0)
617 return(error);
618
619 error = ttioctl(tp, cmd, data, flag, p);
620 if (error >= 0)
621 return(error);
622
623 switch (cmd) {
624 case TIOCSBRK:
625 custom.adkcon = ADKCONF_SETCLR | ADKCONF_UARTBRK;
626 break;
627
628 case TIOCCBRK:
629 custom.adkcon = ADKCONF_UARTBRK;
630 break;
631
632 case TIOCSDTR:
633 (void) sermctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
634 break;
635
636 case TIOCCDTR:
637 (void) sermctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
638 break;
639
640 case TIOCMSET:
641 (void) sermctl(dev, *(int *) data, DMSET);
642 break;
643
644 case TIOCMBIS:
645 (void) sermctl(dev, *(int *) data, DMBIS);
646 break;
647
648 case TIOCMBIC:
649 (void) sermctl(dev, *(int *) data, DMBIC);
650 break;
651
652 case TIOCMGET:
653 *(int *)data = sermctl(dev, 0, DMGET);
654 break;
655 case TIOCGFLAGS:
656 *(int *)data = SWFLAGS(dev);
657 break;
658 case TIOCSFLAGS:
659 error = suser(p->p_ucred, &p->p_acflag);
660 if (error != 0)
661 return(EPERM);
662
663 serswflags = *(int *)data;
664 serswflags &= /* only allow valid flags */
665 (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
666 break;
667 default:
668 return(ENOTTY);
669 }
670
671 return(0);
672 }
673
674 int
675 serparam(tp, t)
676 struct tty *tp;
677 struct termios *t;
678 {
679 int cfcr, cflag, unit, ospeed;
680
681 cflag = t->c_cflag;
682 unit = SERUNIT(tp->t_dev);
683 ospeed = ttspeedtab(t->c_ospeed, serspeedtab);
684
685 if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
686 return(EINVAL);
687
688 /*
689 * copy to tty
690 */
691 tp->t_ispeed = t->c_ispeed;
692 tp->t_ospeed = t->c_ospeed;
693 tp->t_cflag = cflag;
694
695 /*
696 * enable interrupts
697 */
698 custom.intena = INTF_SETCLR | INTF_RBF | INTF_TBE;
699 last_ciab_pra = ciab.pra;
700
701 if (ospeed == 0)
702 (void)sermctl(tp->t_dev, 0, DMSET); /* hang up line */
703 else {
704 /*
705 * (re)enable DTR
706 * and set baud rate. (8 bit mode)
707 */
708 (void)sermctl(tp->t_dev, TIOCM_DTR | TIOCM_RTS, DMSET);
709 custom.serper = (0 << 15) | ospeed;
710 }
711 return(0);
712 }
713
714 int serhwiflow(tp, flag)
715 struct tty *tp;
716 int flag;
717 {
718 #if 0
719 printf ("serhwiflow %d\n", flag);
720 #endif
721 if (flag)
722 CLRRTS(ciab.pra);
723 else
724 SETRTS(ciab.pra);
725 return 1;
726 }
727
728 static void
729 ser_putchar(tp, c)
730 struct tty *tp;
731 u_short c;
732 {
733 if ((tp->t_cflag & CSIZE) == CS7 || (tp->t_cflag & PARENB))
734 c &= 0x7f;
735
736 /*
737 * handle parity if necessary
738 */
739 if (tp->t_cflag & PARENB) {
740 if (even_parity[c])
741 c |= 0x80;
742 if (tp->t_cflag & PARODD)
743 c ^= 0x80;
744 }
745 /*
746 * add stop bit(s)
747 */
748 if (tp->t_cflag & CSTOPB)
749 c |= 0x300;
750 else
751 c |= 0x100;
752
753 custom.serdat = c;
754 }
755
756
757 static u_char ser_outbuf[SEROBUF_SIZE];
758 static u_char *sob_ptr = ser_outbuf, *sob_end = ser_outbuf;
759
760 void
761 ser_outintr()
762 {
763 struct tty *tp = ser_tty[0];
764 u_short c;
765 int s;
766
767 tp = ser_tty[0];
768 s = spltty();
769
770 if (tp == 0)
771 goto out;
772
773 if ((custom.intreqr & INTF_TBE) == 0)
774 goto out;
775
776 /*
777 * clear interrupt
778 */
779 custom.intreq = INTF_TBE;
780
781 if (sob_ptr == sob_end) {
782 tp->t_state &= ~(TS_BUSY | TS_FLUSH);
783 if (tp->t_line)
784 (*linesw[tp->t_line].l_start)(tp);
785 else
786 serstart(tp);
787 goto out;
788 }
789
790 /*
791 * Do hardware flow control here. if the CTS line goes down, don't
792 * transmit anything. That way, we'll be restarted by the periodic
793 * interrupt when CTS comes back up.
794 */
795 if (ISCTS(ciab.pra))
796 ser_putchar(tp, *sob_ptr++);
797 else
798 CLRCTS(last_ciab_pra); /* Remember that CTS is off */
799 out:
800 splx(s);
801 }
802
803 int
804 serstart(tp)
805 struct tty *tp;
806 {
807 int cc, s, unit, hiwat;
808
809 hiwat = 0;
810
811 if ((tp->t_state & TS_ISOPEN) == 0)
812 return;
813
814 unit = SERUNIT(tp->t_dev);
815
816 s = spltty();
817 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
818 goto out;
819
820 cc = tp->t_outq.c_cc;
821 if (cc <= tp->t_lowat) {
822 if (tp->t_state & TS_ASLEEP) {
823 tp->t_state &= ~TS_ASLEEP;
824 wakeup((caddr_t) & tp->t_outq);
825 }
826 selwakeup(&tp->t_wsel);
827 }
828 if (cc == 0 || (tp->t_state & TS_BUSY))
829 goto out;
830
831 /*
832 * We only do bulk transfers if using CTSRTS flow control, not for
833 * (probably sloooow) ixon/ixoff devices.
834 */
835 if ((tp->t_cflag & CRTSCTS) == 0)
836 cc = 1;
837
838 /*
839 * Limit the amount of output we do in one burst
840 * to prevent hogging the CPU.
841 */
842 if (cc > SEROBUF_SIZE) {
843 hiwat++;
844 cc = SEROBUF_SIZE;
845 }
846 cc = q_to_b(&tp->t_outq, ser_outbuf, cc);
847 if (cc > 0) {
848 tp->t_state |= TS_BUSY;
849
850 sob_ptr = ser_outbuf;
851 sob_end = ser_outbuf + cc;
852
853 /*
854 * Get first character out, then have TBE-interrupts blow out
855 * further characters, until buffer is empty, and TS_BUSY gets
856 * cleared.
857 */
858 ser_putchar(tp, *sob_ptr++);
859 }
860 out:
861 splx(s);
862 }
863
864 /*
865 * Stop output on a line.
866 */
867 /*ARGSUSED*/
868 int
869 serstop(tp, flag)
870 struct tty *tp;
871 {
872 int s;
873
874 s = spltty();
875 if (tp->t_state & TS_BUSY) {
876 if ((tp->t_state & TS_TTSTOP) == 0)
877 tp->t_state |= TS_FLUSH;
878 }
879 splx(s);
880 }
881
882 int
883 sermctl(dev, bits, how)
884 dev_t dev;
885 int bits, how;
886 {
887 int unit, s;
888 u_char ub;
889
890 unit = SERUNIT(dev);
891
892 /*
893 * convert TIOCM* mask into CIA mask
894 * which is active low
895 */
896 if (how != DMGET) {
897 ub = 0;
898 if (bits & TIOCM_DTR)
899 ub |= CIAB_PRA_DTR;
900 if (bits & TIOCM_RTS)
901 ub |= CIAB_PRA_RTS;
902 if (bits & TIOCM_CTS)
903 ub |= CIAB_PRA_CTS;
904 if (bits & TIOCM_CD)
905 ub |= CIAB_PRA_CD;
906 if (bits & TIOCM_RI)
907 ub |= CIAB_PRA_SEL; /* collision with /dev/par ! */
908 if (bits & TIOCM_DSR)
909 ub |= CIAB_PRA_DSR;
910 }
911 s = spltty();
912 switch (how) {
913 case DMSET:
914 /* invert and set */
915 ciab.pra = ~ub;
916 break;
917
918 case DMBIC:
919 ciab.pra |= ub;
920 ub = ~ciab.pra;
921 break;
922
923 case DMBIS:
924 ciab.pra &= ~ub;
925 ub = ~ciab.pra;
926 break;
927
928 case DMGET:
929 ub = ~ciab.pra;
930 break;
931 }
932 (void)splx(s);
933
934 bits = 0;
935 if (ub & CIAB_PRA_DTR)
936 bits |= TIOCM_DTR;
937 if (ub & CIAB_PRA_RTS)
938 bits |= TIOCM_RTS;
939 if (ub & CIAB_PRA_CTS)
940 bits |= TIOCM_CTS;
941 if (ub & CIAB_PRA_CD)
942 bits |= TIOCM_CD;
943 if (ub & CIAB_PRA_SEL)
944 bits |= TIOCM_RI;
945 if (ub & CIAB_PRA_DSR)
946 bits |= TIOCM_DSR;
947
948 return(bits);
949 }
950
951 /*
952 * Following are all routines needed for SER to act as console
953 */
954 int
955 sercnprobe(cp)
956 struct consdev *cp;
957 {
958 int unit = CONUNIT;
959
960 /* locate the major number */
961 for (sermajor = 0; sermajor < nchrdev; sermajor++)
962 if (cdevsw[sermajor].d_open == (void *)seropen)
963 break;
964
965
966 unit = CONUNIT; /* XXX: ick */
967
968 /*
969 * initialize required fields
970 */
971 cp->cn_dev = makedev(sermajor, unit);
972 if (serconsole == unit)
973 cp->cn_pri = CN_REMOTE;
974 else
975 cp->cn_pri = CN_NORMAL;
976 #ifdef KGDB
977 if (major(kgdb_dev) == 1) /* XXX */
978 kgdb_dev = makedev(sermajor, minor(kgdb_dev));
979 #endif
980 }
981
982 sercninit(cp)
983 struct consdev *cp;
984 {
985 int unit;
986
987 unit = SERUNIT(cp->cn_dev);
988
989 serinit(unit, serdefaultrate);
990 serconsole = unit;
991 serconsinit = 1;
992 }
993
994 serinit(unit, rate)
995 int unit, rate;
996 {
997 int s;
998
999 s = splhigh();
1000 /*
1001 * might want to fiddle with the CIA later ???
1002 */
1003 custom.serper = ttspeedtab(rate, serspeedtab);
1004 splx(s);
1005 }
1006
1007 sercngetc(dev)
1008 {
1009 u_short stat;
1010 int c, s;
1011
1012 s = splhigh();
1013 /*
1014 * poll
1015 */
1016 while (((stat = custom.serdatr & 0xffff) & SERDATRF_RBF) == 0)
1017 ;
1018 c = stat & 0xff;
1019 /*
1020 * clear interrupt
1021 */
1022 custom.intreq = INTF_RBF;
1023 splx(s);
1024 return(c);
1025 }
1026
1027 /*
1028 * Console kernel output character routine.
1029 */
1030 sercnputc(dev, c)
1031 dev_t dev;
1032 int c;
1033 {
1034 register int timo;
1035 short stat;
1036 int s;
1037
1038 s = splhigh();
1039
1040 if (serconsinit == 0) {
1041 (void)serinit(SERUNIT(dev), serdefaultrate);
1042 serconsinit = 1;
1043 }
1044
1045 /*
1046 * wait for any pending transmission to finish
1047 */
1048 timo = 50000;
1049 while (!(custom.serdatr & SERDATRF_TBE) && --timo);
1050
1051 /*
1052 * transmit char.
1053 */
1054 custom.serdat = (c & 0xff) | 0x100;
1055
1056 /*
1057 * wait for this transmission to complete
1058 */
1059 timo = 1500000;
1060 while (!(custom.serdatr & SERDATRF_TBE) && --timo)
1061 ;
1062
1063 /*
1064 * Wait for the device (my vt100..) to process the data, since we
1065 * don't do flow-control with cnputc
1066 */
1067 for (timo = 0; timo < 30000; timo++)
1068 ;
1069
1070 /*
1071 * clear any interrupts generated by this transmission
1072 */
1073 custom.intreq = INTF_TBE;
1074 splx(s);
1075 }
1076 #endif
1077