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