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