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