ser.c revision 1.20 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.20 1994/06/16 14:28: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();
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 #if 0
431 log(LOG_WARNING, "ser_fastint: buffer overflow!");
432 #else
433 ++sbovfl;
434 #endif
435 return;
436 }
437 /*
438 * store in buffer
439 */
440 *sbwpt++ = code;
441 if (sbwpt == serbuf + SERIBUF_SIZE)
442 sbwpt = serbuf;
443 }
444
445
446 int
447 serintr(unit)
448 int unit;
449 {
450 int s1, s2, ovfl;
451
452 /*
453 * Make sure we're not interrupted by another
454 * vbl, but allow level5 ints
455 */
456 s1 = spltty();
457
458 /*
459 * pass along any acumulated information
460 */
461 while (sbrpt != sbwpt) {
462 /*
463 * no collision with ser_fastint()
464 */
465 sereint(unit, *sbrpt);
466
467 ovfl = 0;
468 /* lock against ser_fastint() */
469 s2 = spl5();
470 sbrpt++;
471 if (sbrpt == serbuf + SERIBUF_SIZE)
472 sbrpt = serbuf;
473 if (sbovfl != 0) {
474 ovfl = sbovfl;
475 sbovfl = 0;
476 }
477 splx(s2);
478 if (ovfl != 0)
479 log(LOG_WARNING, "ser_fastint: %d buffer overflow!\n", ovfl);
480 }
481 splx(s1);
482 }
483
484 int
485 sereint(unit, stat)
486 int unit, stat;
487 {
488 struct tty *tp;
489 u_char ch;
490 int c;
491
492 tp = ser_tty[unit];
493 ch = stat & 0xff;
494 c = ch;
495
496 if ((tp->t_state & TS_ISOPEN) == 0) {
497 #ifdef KGDB
498 /* we don't care about parity errors */
499 if (kgdb_dev == makedev(sermajor, unit) && c == FRAME_END)
500 kgdb_connect(0); /* trap into kgdb */
501 #endif
502 return;
503 }
504
505 /*
506 * Check for break and (if enabled) parity error.
507 */
508 if ((stat & 0x1ff) == 0)
509 c |= TTY_FE;
510 else if ((tp->t_cflag & PARENB) &&
511 (((ch >> 7) + even_parity[ch & 0x7f]
512 + !!(tp->t_cflag & PARODD)) & 1))
513 c |= TTY_PE;
514
515 if (stat & SERDATRF_OVRUN)
516 log(LOG_WARNING, "ser0: silo overflow\n");
517
518 (*linesw[tp->t_line].l_rint)(c, tp);
519 }
520
521 /*
522 * This interrupt is periodically invoked in the vertical blank
523 * interrupt. It's used to keep track of the modem control lines
524 * and (new with the fast_int code) to move accumulated data
525 * up into the tty layer.
526 */
527 void
528 sermint(unit)
529 int unit;
530 {
531 struct tty *tp;
532 u_char stat, last, istat;
533
534 tp = ser_tty[unit];
535 if (!tp)
536 return;
537
538 if ((tp->t_state & (TS_ISOPEN | TS_WOPEN)) == 0) {
539 sbrpt = sbwpt = serbuf;
540 return;
541 }
542 /*
543 * empty buffer
544 */
545 serintr(unit);
546
547 stat = ciab.pra;
548 last = last_ciab_pra;
549 last_ciab_pra = stat;
550
551 /*
552 * check whether any interesting signal changed state
553 */
554 istat = stat ^ last;
555
556 if ((istat & CIAB_PRA_CD) &&
557 (SWFLAGS(tp->t_dev) & TIOCFLAG_SOFTCAR) == 0) {
558 if (ISDCD(stat))
559 (*linesw[tp->t_line].l_modem)(tp, 1);
560 else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
561 CLRDTR(stat);
562 CLRRTS(stat);
563 ciab.pra = stat;
564 last_ciab_pra = stat;
565 }
566 }
567 if ((istat & CIAB_PRA_CTS) && (tp->t_state & TS_ISOPEN) &&
568 (tp->t_cflag & CRTSCTS)) {
569 #if 0
570 /* the line is up and we want to do rts/cts flow control */
571 if (ISCTS(stat)) {
572 tp->t_state &= ~TS_TTSTOP;
573 ttstart(tp);
574 /* cause tbe-int if we were stuck there */
575 custom.intreq = INTF_SETCLR | INTF_TBE;
576 } else
577 tp->t_state |= TS_TTSTOP;
578 #else
579 /* do this on hardware level, not with tty driver */
580 if (ISCTS(stat)) {
581 tp->t_state &= ~TS_TTSTOP;
582 /* cause TBE interrupt */
583 custom.intreq = INTF_SETCLR | INTF_TBE;
584 }
585 #endif
586 }
587 }
588
589 int
590 serioctl(dev, cmd, data, flag, p)
591 dev_t dev;
592 caddr_t data;
593 struct proc *p;
594 {
595 register struct tty *tp;
596 register int unit = SERUNIT(dev);
597 register int error;
598
599 tp = ser_tty[unit];
600 if (!tp)
601 return ENXIO;
602
603 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
604 if (error >= 0)
605 return(error);
606
607 error = ttioctl(tp, cmd, data, flag, p);
608 if (error >= 0)
609 return(error);
610
611 switch (cmd) {
612 case TIOCSBRK:
613 custom.adkcon = ADKCONF_SETCLR | ADKCONF_UARTBRK;
614 break;
615
616 case TIOCCBRK:
617 custom.adkcon = ADKCONF_UARTBRK;
618 break;
619
620 case TIOCSDTR:
621 (void) sermctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
622 break;
623
624 case TIOCCDTR:
625 (void) sermctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
626 break;
627
628 case TIOCMSET:
629 (void) sermctl(dev, *(int *) data, DMSET);
630 break;
631
632 case TIOCMBIS:
633 (void) sermctl(dev, *(int *) data, DMBIS);
634 break;
635
636 case TIOCMBIC:
637 (void) sermctl(dev, *(int *) data, DMBIC);
638 break;
639
640 case TIOCMGET:
641 *(int *)data = sermctl(dev, 0, DMGET);
642 break;
643 case TIOCGFLAGS:
644 *(int *)data = SWFLAGS(dev);
645 break;
646 case TIOCSFLAGS:
647 error = suser(p->p_ucred, &p->p_acflag);
648 if (error != 0)
649 return(EPERM);
650
651 serswflags = *(int *)data;
652 serswflags &= /* only allow valid flags */
653 (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
654 break;
655 default:
656 return(ENOTTY);
657 }
658
659 return(0);
660 }
661
662 int
663 serparam(tp, t)
664 struct tty *tp;
665 struct termios *t;
666 {
667 int cfcr, cflag, unit, ospeed;
668
669 cflag = t->c_cflag;
670 unit = SERUNIT(tp->t_dev);
671 ospeed = ttspeedtab(t->c_ospeed, serspeedtab);
672
673 if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
674 return(EINVAL);
675
676 /*
677 * copy to tty
678 */
679 tp->t_ispeed = t->c_ispeed;
680 tp->t_ospeed = t->c_ospeed;
681 tp->t_cflag = cflag;
682
683 /*
684 * enable interrupts
685 */
686 custom.intena = INTF_SETCLR | INTF_RBF | INTF_TBE;
687 last_ciab_pra = ciab.pra;
688
689 if (ospeed == 0)
690 (void)sermctl(tp->t_dev, 0, DMSET); /* hang up line */
691 else {
692 /*
693 * (re)enable DTR
694 * and set baud rate. (8 bit mode)
695 */
696 (void)sermctl(tp->t_dev, TIOCM_DTR | TIOCM_RTS, DMSET);
697 custom.serper = (0 << 15) | ospeed;
698 }
699 return(0);
700 }
701
702
703 static void
704 ser_putchar(tp, c)
705 struct tty *tp;
706 u_short c;
707 {
708 if ((tp->t_cflag & CSIZE) == CS7 || (tp->t_cflag & PARENB))
709 c &= 0x7f;
710
711 /*
712 * handle parity if necessary
713 */
714 if (tp->t_cflag & PARENB) {
715 if (even_parity[c])
716 c |= 0x80;
717 if (tp->t_cflag & PARODD)
718 c ^= 0x80;
719 }
720 /*
721 * add stop bit(s)
722 */
723 if (tp->t_cflag & CSTOPB)
724 c |= 0x300;
725 else
726 c |= 0x100;
727
728 custom.serdat = c;
729 }
730
731
732 static u_char ser_outbuf[SEROBUF_SIZE];
733 static u_char *sob_ptr = ser_outbuf, *sob_end = ser_outbuf;
734
735 void
736 ser_outintr()
737 {
738 struct tty *tp = ser_tty[0];
739 u_short c;
740 int s;
741
742 tp = ser_tty[0];
743 s = spltty();
744
745 if (tp == 0)
746 goto out;
747
748 if ((custom.intreqr & INTF_TBE) == 0)
749 goto out;
750
751 /*
752 * clear interrupt
753 */
754 custom.intreq = INTF_TBE;
755
756 if (sob_ptr == sob_end) {
757 tp->t_state &= ~(TS_BUSY | TS_FLUSH);
758 if (tp->t_line)
759 (*linesw[tp->t_line].l_start)(tp);
760 else
761 serstart(tp);
762 goto out;
763 }
764
765 /*
766 * Do hardware flow control here. if the CTS line goes down, don't
767 * transmit anything. That way, we'll be restarted by the periodic
768 * interrupt when CTS comes back up.
769 */
770 if (ISCTS(ciab.pra))
771 ser_putchar(tp, *sob_ptr++);
772 out:
773 splx(s);
774 }
775
776 int
777 serstart(tp)
778 struct tty *tp;
779 {
780 int cc, s, unit, hiwat;
781
782 hiwat = 0;
783
784 if ((tp->t_state & TS_ISOPEN) == 0)
785 return;
786
787 unit = SERUNIT(tp->t_dev);
788
789 s = spltty();
790 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
791 goto out;
792
793 cc = tp->t_outq.c_cc;
794 if (cc <= tp->t_lowat) {
795 if (tp->t_state & TS_ASLEEP) {
796 tp->t_state &= ~TS_ASLEEP;
797 wakeup((caddr_t) & tp->t_outq);
798 }
799 selwakeup(&tp->t_wsel);
800 }
801 if (cc == 0 || (tp->t_state & TS_BUSY))
802 goto out;
803
804 /*
805 * We only do bulk transfers if using CTSRTS flow control, not for
806 * (probably sloooow) ixon/ixoff devices.
807 */
808 if ((tp->t_cflag & CRTSCTS) == 0)
809 cc = 1;
810
811 /*
812 * Limit the amount of output we do in one burst
813 * to prevent hogging the CPU.
814 */
815 if (cc > SEROBUF_SIZE) {
816 hiwat++;
817 cc = SEROBUF_SIZE;
818 }
819 cc = q_to_b(&tp->t_outq, ser_outbuf, cc);
820 if (cc > 0) {
821 tp->t_state |= TS_BUSY;
822
823 sob_ptr = ser_outbuf;
824 sob_end = ser_outbuf + cc;
825
826 /*
827 * Get first character out, then have TBE-interrupts blow out
828 * further characters, until buffer is empty, and TS_BUSY gets
829 * cleared.
830 */
831 ser_putchar(tp, *sob_ptr++);
832 }
833 out:
834 splx(s);
835 }
836
837 /*
838 * Stop output on a line.
839 */
840 /*ARGSUSED*/
841 int
842 serstop(tp, flag)
843 struct tty *tp;
844 {
845 int s;
846
847 s = spltty();
848 if (tp->t_state & TS_BUSY) {
849 if ((tp->t_state & TS_TTSTOP) == 0)
850 tp->t_state |= TS_FLUSH;
851 }
852 splx(s);
853 }
854
855 int
856 sermctl(dev, bits, how)
857 dev_t dev;
858 int bits, how;
859 {
860 int unit, s;
861 u_char ub;
862
863 unit = SERUNIT(dev);
864
865 /*
866 * convert TIOCM* mask into CIA mask
867 * which is active low
868 */
869 if (how != DMGET) {
870 ub = 0;
871 if (bits & TIOCM_DTR)
872 ub |= CIAB_PRA_DTR;
873 if (bits & TIOCM_RTS)
874 ub |= CIAB_PRA_RTS;
875 if (bits & TIOCM_CTS)
876 ub |= CIAB_PRA_CTS;
877 if (bits & TIOCM_CD)
878 ub |= CIAB_PRA_CD;
879 if (bits & TIOCM_RI)
880 ub |= CIAB_PRA_SEL; /* collision with /dev/par ! */
881 if (bits & TIOCM_DSR)
882 ub |= CIAB_PRA_DSR;
883 }
884 s = spltty();
885 switch (how) {
886 case DMSET:
887 /* invert and set */
888 ciab.pra = ~ub;
889 break;
890
891 case DMBIC:
892 ciab.pra |= ub;
893 ub = ~ciab.pra;
894 break;
895
896 case DMBIS:
897 ciab.pra &= ~ub;
898 ub = ~ciab.pra;
899 break;
900
901 case DMGET:
902 ub = ~ciab.pra;
903 break;
904 }
905 (void)splx(s);
906
907 bits = 0;
908 if (ub & CIAB_PRA_DTR)
909 bits |= TIOCM_DTR;
910 if (ub & CIAB_PRA_RTS)
911 bits |= TIOCM_RTS;
912 if (ub & CIAB_PRA_CTS)
913 bits |= TIOCM_CTS;
914 if (ub & CIAB_PRA_CD)
915 bits |= TIOCM_CD;
916 if (ub & CIAB_PRA_SEL)
917 bits |= TIOCM_RI;
918 if (ub & CIAB_PRA_DSR)
919 bits |= TIOCM_DSR;
920
921 return(bits);
922 }
923
924 /*
925 * Following are all routines needed for SER to act as console
926 */
927 int
928 sercnprobe(cp)
929 struct consdev *cp;
930 {
931 int unit = CONUNIT;
932
933 /* locate the major number */
934 for (sermajor = 0; sermajor < nchrdev; sermajor++)
935 if (cdevsw[sermajor].d_open == (void *)seropen)
936 break;
937
938
939 unit = CONUNIT; /* XXX: ick */
940
941 /*
942 * initialize required fields
943 */
944 cp->cn_dev = makedev(sermajor, unit);
945 if (serconsole == unit)
946 cp->cn_pri = CN_REMOTE;
947 else
948 cp->cn_pri = CN_NORMAL;
949 #ifdef KGDB
950 if (major(kgdb_dev) == 1) /* XXX */
951 kgdb_dev = makedev(sermajor, minor(kgdb_dev));
952 #endif
953 }
954
955 sercninit(cp)
956 struct consdev *cp;
957 {
958 int unit;
959
960 unit = SERUNIT(cp->cn_dev);
961
962 serinit(unit, serdefaultrate);
963 serconsole = unit;
964 serconsinit = 1;
965 }
966
967 serinit(unit, rate)
968 int unit, rate;
969 {
970 int s;
971
972 s = splhigh();
973 /*
974 * might want to fiddle with the CIA later ???
975 */
976 custom.serper = ttspeedtab(rate, serspeedtab);
977 splx(s);
978 }
979
980 sercngetc(dev)
981 {
982 u_short stat;
983 int c, s;
984
985 s = splhigh();
986 /*
987 * poll
988 */
989 while (((stat = custom.serdatr & 0xffff) & SERDATRF_RBF) == 0)
990 ;
991 c = stat & 0xff;
992 /*
993 * clear interrupt
994 */
995 custom.intreq = INTF_RBF;
996 splx(s);
997 return(c);
998 }
999
1000 /*
1001 * Console kernel output character routine.
1002 */
1003 sercnputc(dev, c)
1004 dev_t dev;
1005 int c;
1006 {
1007 register int timo;
1008 short stat;
1009 int s;
1010
1011 s = splhigh();
1012
1013 if (serconsinit == 0) {
1014 (void)serinit(SERUNIT(dev), serdefaultrate);
1015 serconsinit = 1;
1016 }
1017
1018 /*
1019 * wait for any pending transmission to finish
1020 */
1021 timo = 50000;
1022 while (!(custom.serdatr & SERDATRF_TBE) && --timo);
1023
1024 /*
1025 * transmit char.
1026 */
1027 custom.serdat = (c & 0xff) | 0x100;
1028
1029 /*
1030 * wait for this transmission to complete
1031 */
1032 timo = 1500000;
1033 while (!(custom.serdatr & SERDATRF_TBE) && --timo)
1034 ;
1035
1036 /*
1037 * Wait for the device (my vt100..) to process the data, since we
1038 * don't do flow-control with cnputc
1039 */
1040 for (timo = 0; timo < 30000; timo++)
1041 ;
1042
1043 /*
1044 * clear any interrupts generated by this transmission
1045 */
1046 custom.intreq = INTF_TBE;
1047 splx(s);
1048 }
1049 #endif
1050