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