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