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