ser.c revision 1.6 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 */
35
36 #include "ser.h"
37
38 #if NSER > 0
39 #include "sys/param.h"
40 #include "sys/systm.h"
41 #include "sys/ioctl.h"
42 #include "sys/tty.h"
43 #include "sys/proc.h"
44 #include "sys/conf.h"
45 #include "sys/file.h"
46 #include "sys/malloc.h"
47 #include "sys/uio.h"
48 #include "sys/kernel.h"
49 #include "sys/syslog.h"
50
51 #include "device.h"
52 #include "serreg.h"
53 #include "machine/cpu.h"
54
55 #include "../amiga/custom.h"
56 #include "../amiga/cia.h"
57 #include "../amiga/cc.h"
58
59 int serprobe();
60 struct driver serdriver = {
61 serprobe, "ser",
62 };
63
64 int serstart(), serparam(), serintr();
65 extern int ttrstrt();
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)
566 dev_t dev;
567 caddr_t data;
568 {
569 register struct tty *tp;
570 register int unit = SERUNIT(dev);
571 register struct serdevice *ser;
572 register int error;
573
574 tp = ser_tty[unit];
575 if (! tp)
576 return ENXIO;
577
578 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
579 if (error >= 0)
580 return (error);
581
582 error = ttioctl(tp, cmd, data, flag);
583 if (error >= 0)
584 return (error);
585
586 ser = ser_addr[unit];
587 switch (cmd)
588 {
589 case TIOCSBRK:
590 custom.adkcon = ADKCONF_SETCLR | ADKCONF_UARTBRK;
591 break;
592
593 case TIOCCBRK:
594 custom.adkcon = ADKCONF_UARTBRK;
595 break;
596
597 case TIOCSDTR:
598 (void) sermctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
599 break;
600
601 case TIOCCDTR:
602 (void) sermctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
603 break;
604
605 case TIOCMSET:
606 (void) sermctl(dev, *(int *)data, DMSET);
607 break;
608
609 case TIOCMBIS:
610 (void) sermctl(dev, *(int *)data, DMBIS);
611 break;
612
613 case TIOCMBIC:
614 (void) sermctl(dev, *(int *)data, DMBIC);
615 break;
616
617 case TIOCMGET:
618 *(int *)data = sermctl(dev, 0, DMGET);
619 break;
620
621 default:
622 return (ENOTTY);
623 }
624
625 return (0);
626 }
627
628 int
629 serparam(tp, t)
630 register struct tty *tp;
631 register struct termios *t;
632 {
633 register struct serdevice *ser;
634 register int cfcr, cflag = t->c_cflag;
635 int unit = SERUNIT(tp->t_dev);
636 int ospeed = ttspeedtab(t->c_ospeed, serspeedtab);
637
638 /* check requested parameters */
639 if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
640 return (EINVAL);
641
642 /* and copy to tty */
643 tp->t_ispeed = t->c_ispeed;
644 tp->t_ospeed = t->c_ospeed;
645 tp->t_cflag = cflag;
646
647 custom.intena = INTF_SETCLR | INTF_RBF | INTF_TBE;
648 last_ciab_pra = ciab.pra;
649
650 if (ospeed == 0)
651 {
652 (void) sermctl(tp->t_dev, 0, DMSET); /* hang up line */
653 return (0);
654 }
655 else
656 {
657 /* make sure any previous hangup is undone, ie.
658 reenable DTR. */
659 (void) sermctl (tp->t_dev, TIOCM_DTR | TIOCM_RTS, DMSET);
660 }
661 /* set the baud rate */
662 custom.serper = (0<<15) | ospeed; /* select 8 bit mode (instead of 9 bit) */
663
664 return (0);
665 }
666
667
668 static void
669 ser_putchar (tp, c)
670 struct tty *tp;
671 unsigned short c;
672 {
673 /* handle truncation of character if necessary */
674 if ((tp->t_cflag & CSIZE) == CS7)
675 c &= 0x7f;
676
677 /* handle parity if necessary (forces CS7) */
678 if (tp->t_cflag & PARENB)
679 {
680 c &= 0x7f;
681 if (even_parity[c])
682 c |= 0x80;
683 if (tp->t_cflag & PARODD)
684 c ^= 0x80;
685 }
686
687 /* add stop bit(s) */
688 if (tp->t_cflag & CSTOPB)
689 c |= 0x300;
690 else
691 c |= 0x100;
692
693 custom.serdat = c;
694 }
695
696
697 #define SEROBUF_SIZE 32
698 static u_char ser_outbuf[SEROBUF_SIZE];
699 static u_char *sob_ptr=ser_outbuf, *sob_end=ser_outbuf;
700 void
701 ser_outintr ()
702 {
703 struct tty *tp = ser_tty[0]; /* hmmmmm */
704 unsigned short c;
705 int s = spltty ();
706
707 if (! tp)
708 goto out;
709
710 if (! (custom.intreqr & INTF_TBE))
711 goto out;
712
713 /* clear interrupt */
714 custom.intreq = INTF_TBE;
715
716 if (sob_ptr == sob_end)
717 {
718 tp->t_state &= ~(TS_BUSY|TS_FLUSH);
719 if (tp->t_line)
720 (*linesw[tp->t_line].l_start)(tp);
721 else
722 serstart (tp);
723
724 goto out;
725 }
726
727 /* do hardware flow control here. if the CTS line goes down, don't
728 transmit anything. That way, we'll be restarted by the periodic
729 interrupt when CTS comes back up. */
730 if (ISCTS (ciab.pra))
731 ser_putchar (tp, *sob_ptr++);
732 out:
733 splx (s);
734 }
735
736 int
737 serstart(tp)
738 register struct tty *tp;
739 {
740 register int cc, s;
741 int unit;
742 register struct serdevice *ser;
743 int hiwat = 0;
744
745 if (! (tp->t_state & TS_ISOPEN))
746 return;
747
748 unit = SERUNIT(tp->t_dev);
749 ser = ser_addr[unit];
750
751 s = spltty();
752 if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
753 goto out;
754
755 cc = tp->t_outq.c_cc;
756 if (cc <= tp->t_lowat)
757 {
758 if (tp->t_state & TS_ASLEEP)
759 {
760 tp->t_state &= ~TS_ASLEEP;
761 wakeup((caddr_t)&tp->t_outq);
762 }
763 selwakeup(&tp->t_wsel);
764 }
765
766 if (! cc || (tp->t_state & TS_BUSY))
767 goto out;
768
769 /* we only do bulk transfers if using CTSRTS flow control,
770 not for (probably sloooow) ixon/ixoff devices. */
771 if (! (tp->t_cflag & CRTSCTS))
772 cc = 1;
773
774 /*
775 * Limit the amount of output we do in one burst
776 * to prevent hogging the CPU.
777 */
778 if (cc > SEROBUF_SIZE)
779 {
780 hiwat++;
781 cc = SEROBUF_SIZE;
782 }
783 cc = q_to_b (&tp->t_outq, ser_outbuf, cc);
784 if (cc > 0)
785 {
786 tp->t_state |= TS_BUSY;
787
788 sob_ptr = ser_outbuf;
789 sob_end = ser_outbuf + cc;
790 /* get first character out, then have tbe-interrupts blow out
791 further characters, until buffer is empty, and TS_BUSY
792 gets cleared. */
793 ser_putchar (tp, *sob_ptr++);
794 }
795
796 out:
797 splx(s);
798 }
799
800 /*
801 * Stop output on a line.
802 */
803 /*ARGSUSED*/
804 int
805 serstop(tp, flag)
806 register struct tty *tp;
807 {
808 register int s;
809
810 s = spltty();
811 if (tp->t_state & TS_BUSY)
812 {
813 if ((tp->t_state & TS_TTSTOP) == 0)
814 tp->t_state |= TS_FLUSH;
815 }
816 splx(s);
817 }
818
819 int
820 sermctl(dev, bits, how)
821 dev_t dev;
822 int bits, how;
823 {
824 register struct serdevice *ser;
825 register int unit;
826 u_char ub;
827 int s;
828
829 unit = SERUNIT(dev);
830 ser = ser_addr[unit];
831
832 /* convert TIOCM* mask into CIA mask (which is really low-active!!) */
833 if (how != DMGET)
834 {
835 ub = 0;
836 if (bits & TIOCM_DTR) ub |= CIAB_PRA_DTR;
837 if (bits & TIOCM_RTS) ub |= CIAB_PRA_RTS;
838 if (bits & TIOCM_CTS) ub |= CIAB_PRA_CTS;
839 if (bits & TIOCM_CD) ub |= CIAB_PRA_CD;
840 if (bits & TIOCM_RI) ub |= CIAB_PRA_SEL; /* collision with /dev/par ! */
841 if (bits & TIOCM_DSR) ub |= CIAB_PRA_DSR;
842 }
843
844
845 s = spltty();
846 switch (how)
847 {
848 case DMSET:
849 /* invert and set */
850 ciab.pra = ~ub;
851 break;
852
853 case DMBIC:
854 ciab.pra |= ub;
855 ub = ~ciab.pra;
856 break;
857
858 case DMBIS:
859 ciab.pra &= ~ub;
860 ub = ~ciab.pra;
861 break;
862
863 case DMGET:
864 ub = ~ciab.pra;
865 break;
866 }
867 (void) splx(s);
868
869 bits = 0;
870 if (ub & CIAB_PRA_DTR) bits |= TIOCM_DTR;
871 if (ub & CIAB_PRA_RTS) bits |= TIOCM_RTS;
872 if (ub & CIAB_PRA_CTS) bits |= TIOCM_CTS;
873 if (ub & CIAB_PRA_CD) bits |= TIOCM_CD;
874 if (ub & CIAB_PRA_SEL) bits |= TIOCM_RI;
875 if (ub & CIAB_PRA_DSR) bits |= TIOCM_DSR;
876
877 return bits;
878 }
879
880 /*
881 * Following are all routines needed for SER to act as console
882 */
883 #include "../amiga/cons.h"
884
885 sercnprobe(cp)
886 struct consdev *cp;
887 {
888 int unit = CONUNIT;
889 /* locate the major number */
890 for (sermajor = 0; sermajor < nchrdev; sermajor++)
891 if (cdevsw[sermajor].d_open == seropen)
892 break;
893
894 /* XXX: ick */
895 unit = CONUNIT;
896
897 /* initialize required fields */
898 cp->cn_dev = makedev(sermajor, unit);
899 #if 0
900 /* on ser it really doesn't matter whether we're later
901 using the tty interface or single-character io thru
902 cnputc, so don't reach out to later on remember that
903 our console is here (see ite.c) */
904 cp->cn_tp = ser_tty[unit];
905 #endif
906 cp->cn_pri = CN_NORMAL;
907
908 /*
909 * If serconsole is initialized, raise our priority.
910 */
911 if (serconsole == unit)
912 cp->cn_pri = CN_REMOTE;
913 #ifdef KGDB
914 if (major(kgdb_dev) == 1) /* XXX */
915 kgdb_dev = makedev(sermajor, minor(kgdb_dev));
916 #endif
917 }
918
919 sercninit(cp)
920 struct consdev *cp;
921 {
922 int unit = SERUNIT(cp->cn_dev);
923
924 serinit(unit, serdefaultrate);
925 serconsole = unit;
926 serconsinit = 1;
927 }
928
929 serinit(unit, rate)
930 int unit, rate;
931 {
932 int s;
933
934 #ifdef lint
935 stat = unit; if (stat) return;
936 #endif
937 s = splhigh();
938 /* might want to fiddle with the CIA later ??? */
939 custom.serper = ttspeedtab(rate, serspeedtab);
940 splx(s);
941 }
942
943 sercngetc(dev)
944 {
945 u_short stat;
946 int c, s;
947
948 #ifdef lint
949 stat = dev; if (stat) return (0);
950 #endif
951 s = splhigh();
952 while (!((stat = custom.serdatr & 0xffff) & SERDATRF_RBF))
953 ;
954 c = stat & 0xff;
955 /* clear interrupt */
956 custom.intreq = INTF_RBF;
957 splx(s);
958 return (c);
959 }
960
961 /*
962 * Console kernel output character routine.
963 */
964 sercnputc(dev, c)
965 dev_t dev;
966 register int c;
967 {
968 register int timo;
969 short stat;
970 int s = splhigh();
971
972 #ifdef lint
973 stat = dev; if (stat) return;
974 #endif
975 if (serconsinit == 0)
976 {
977 (void) serinit(SERUNIT(dev), serdefaultrate);
978 serconsinit = 1;
979 }
980
981 /* wait for any pending transmission to finish */
982 timo = 50000;
983 while (! (custom.serdatr & SERDATRF_TBE) && --timo)
984 ;
985
986 custom.serdat = (c&0xff) | 0x100;
987 /* wait for this transmission to complete */
988 timo = 1500000;
989 while (! (custom.serdatr & SERDATRF_TBE) && --timo)
990 ;
991
992 /* wait for the device (my vt100..) to process the data, since
993 we don't do flow-control with cnputc */
994 for (timo = 0; timo < 30000; timo++) ;
995
996 /* clear any interrupts generated by this transmission */
997 custom.intreq = INTF_TBE;
998 splx(s);
999 }
1000
1001
1002 serspit(c)
1003 int c;
1004 {
1005 register struct Custom *cu asm("a2") = (struct Custom *)CUSTOMbase;
1006 register int timo asm("d2");
1007 extern int cold;
1008 int s;
1009
1010 if (c == 10)
1011 serspit (13);
1012
1013 s = splhigh();
1014
1015 /* wait for any pending transmission to finish */
1016 timo = 500000;
1017 while (! (cu->serdatr & (SERDATRF_TBE|SERDATRF_TSRE)) && --timo)
1018 ;
1019 cu->serdat = (c&0xff) | 0x100;
1020 /* wait for this transmission to complete */
1021 timo = 15000000;
1022 while (! (cu->serdatr & SERDATRF_TBE) && --timo)
1023 ;
1024 /* clear any interrupts generated by this transmission */
1025 cu->intreq = INTF_TBE;
1026
1027 for (timo = 0; timo < 30000; timo++) ;
1028
1029 splx (s);
1030 }
1031
1032 serspits(cp)
1033 char *cp;
1034 {
1035 while (*cp)
1036 serspit(*cp++);
1037 }
1038
1039 int
1040 serselect(dev, rw, p)
1041 dev_t dev;
1042 int rw;
1043 struct proc *p;
1044 {
1045 register struct tty *tp = ser_tty[SERUNIT(dev)];
1046 int nread;
1047 int s = spltty();
1048 struct proc *selp;
1049
1050 switch (rw)
1051 {
1052 case FREAD:
1053 nread = ttnread(tp);
1054 if (nread > 0 || ((tp->t_cflag&CLOCAL) == 0
1055 && (tp->t_state&TS_CARR_ON) == 0))
1056 goto win;
1057 selrecord(p, &tp->t_rsel);
1058 break;
1059
1060 case FWRITE:
1061 if (tp->t_outq.c_cc <= tp->t_lowat)
1062 goto win;
1063 selrecord(p, &tp->t_wsel);
1064 break;
1065 }
1066 splx(s);
1067 return (0);
1068
1069 win:
1070 splx(s);
1071 return (1);
1072 }
1073
1074 #endif
1075