ser.c revision 1.8 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 int ser_active;
66 int ser_hasfifo;
67 int nser = NSER;
68 #ifdef SERCONSOLE
69 int serconsole = SERCONSOLE;
70 #else
71 int serconsole = -1;
72 #endif
73 int serconsinit;
74 int serdefaultrate = TTYDEF_SPEED;
75 int sermajor;
76 struct serdevice *ser_addr[NSER];
77 struct vbl_node ser_vbl_node[NSER];
78 struct tty ser_cons;
79 struct tty *ser_tty[NSER];
80
81 struct speedtab serspeedtab[] = {
82 0, 0,
83 50, SERBRD(50),
84 75, SERBRD(75),
85 110, SERBRD(110),
86 134, SERBRD(134),
87 150, SERBRD(150),
88 200, SERBRD(200),
89 300, SERBRD(300),
90 600, SERBRD(600),
91 1200, SERBRD(1200),
92 1800, SERBRD(1800),
93 2400, SERBRD(2400),
94 4800, SERBRD(4800),
95 9600, SERBRD(9600),
96 19200, SERBRD(19200),
97 38400, SERBRD(38400),
98 -1, -1
99 };
100
101
102 /* since this UART is not particularly bright (nice put), we'll have to do
103 parity stuff on our own. this table contains the 8th bit in 7bit character
104 mode, for even parity. If you want odd parity, flip the bit. (for
105 generation of the table, see genpar.c) */
106
107 u_char even_parity[] = {
108 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
109 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
110 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
111 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
112 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
113 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
114 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
115 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
116 };
117
118
119 /* since we don't get interrupts for changes on the modem control line,
120 well have to fake them by comparing current settings to the settings
121 we remembered on last invocation. */
122 u_char last_ciab_pra;
123
124 extern struct tty *constty;
125 #ifdef KGDB
126 #include "machine/remote-sl.h"
127
128 extern dev_t kgdb_dev;
129 extern int kgdb_rate;
130 extern int kgdb_debug_init;
131 #endif
132
133 #ifdef DEBUG
134 long fifoin[17];
135 long fifoout[17];
136 long serintrcount[16];
137 long sermintcount[16];
138 #endif
139
140 void sermint (register int unit);
141
142 int
143 serprobe(ad)
144 register struct amiga_device *ad;
145 {
146 register struct serdevice *ser;
147 register int unit;
148 unsigned short ir = custom.intenar;
149
150 ser = (struct serdevice *) ad->amiga_addr;
151 unit = ad->amiga_unit;
152 if (unit == serconsole)
153 DELAY(100000);
154
155 ad->amiga_ipl = 2;
156 ser_addr[unit] = ser;
157 ser_active |= 1 << unit;
158 ser_vbl_node[unit].function = (void (*)(void *))sermint;
159 add_vbl_function (&ser_vbl_node[unit], SER_VBL_PRIORITY, (void *)unit);
160 #ifdef KGDB
161 if (kgdb_dev == makedev(sermajor, unit)) {
162 if (serconsole == unit)
163 kgdb_dev = NODEV; /* can't debug over console port */
164 else {
165 (void) serinit(unit, kgdb_rate);
166 serconsinit = 1; /* don't re-init in serputc */
167 if (kgdb_debug_init) {
168 /*
169 * Print prefix of device name,
170 * let kgdb_connect print the rest.
171 */
172 printf("ser%d: ", unit);
173 kgdb_connect(1);
174 } else
175 printf("ser%d: kgdb enabled\n", unit);
176 }
177 }
178 #endif
179 /*
180 * Need to reset baud rate, etc. of next print so reset serconsinit.
181 */
182 if (unit == serconsole)
183 serconsinit = 0;
184
185 return (1);
186 }
187
188 /* ARGSUSED */
189 int
190 #ifdef __STDC__
191 seropen(dev_t dev, int flag, int mode, struct proc *p)
192 #else
193 seropen(dev, flag, mode, p)
194 dev_t dev;
195 int flag, mode;
196 struct proc *p;
197 #endif
198 {
199 register struct tty *tp;
200 register int unit;
201 int error = 0;
202 int s;
203
204 unit = SERUNIT(dev);
205
206 if (unit >= NSER || (ser_active & (1 << unit)) == 0)
207 return (ENXIO);
208 if(!ser_tty[unit])
209 {
210 tp = ser_tty[unit] = ttymalloc();
211 /* default values are not optimal for this device, increase
212 buffers */
213 clfree(&tp->t_rawq);
214 clfree(&tp->t_canq);
215 clfree(&tp->t_outq);
216 clalloc(&tp->t_rawq, 8192, 1);
217 clalloc(&tp->t_canq, 8192, 1);
218 clalloc(&tp->t_outq, 8192, 0);
219 }
220 else
221 tp = ser_tty[unit];
222
223 tp->t_oproc = (void (*)(struct tty *)) serstart;
224 tp->t_param = serparam;
225 tp->t_dev = dev;
226
227 if ((tp->t_state & TS_ISOPEN) == 0)
228 {
229 tp->t_state |= TS_WOPEN;
230 ttychars(tp);
231 if (tp->t_ispeed == 0)
232 {
233 tp->t_iflag = TTYDEF_IFLAG | IXOFF; /* XXXXX */
234 tp->t_oflag = TTYDEF_OFLAG;
235 #if 0
236 tp->t_cflag = TTYDEF_CFLAG;
237 #else
238 tp->t_cflag = (CREAD | CS8 | CLOCAL); /* XXXXX */
239 #endif
240 tp->t_lflag = TTYDEF_LFLAG;
241 tp->t_ispeed = tp->t_ospeed = serdefaultrate;
242 }
243 serparam(tp, &tp->t_termios);
244 ttsetwater(tp);
245 }
246 else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
247 return (EBUSY);
248
249 (void) sermctl (dev, TIOCM_DTR | TIOCM_RTS, DMSET);
250
251 if (DIALOUT(dev) || (sermctl (dev, 0, DMGET) & TIOCM_CD))
252 tp->t_state |= TS_CARR_ON;
253
254 s = spltty();
255 while ((flag & O_NONBLOCK) == 0
256 && (tp->t_cflag & CLOCAL) == 0
257 && (tp->t_state & TS_CARR_ON) == 0)
258 {
259 tp->t_state |= TS_WOPEN;
260 if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
261 ttopen, 0))
262 break;
263 }
264 splx (s);
265 if (error == 0)
266 {
267 /* reset the tty pointer, as there could have been a dialout
268 use of the tty with a dialin open waiting. */
269 tp->t_dev = dev;
270 error = (*linesw[tp->t_line].l_open)(dev, tp);
271 }
272 return (error);
273 }
274
275 /*ARGSUSED*/
276 int
277 serclose(dev, flag, mode, p)
278 dev_t dev;
279 int flag, mode;
280 struct proc *p;
281 {
282 register struct tty *tp;
283 register struct serdevice *ser;
284 register int unit;
285
286 unit = SERUNIT(dev);
287
288 ser = ser_addr[unit];
289 tp = ser_tty[unit];
290 (*linesw[tp->t_line].l_close)(tp, flag);
291 custom.adkcon = ADKCONF_UARTBRK; /* clear break */
292 #ifdef KGDB
293 /* do not disable interrupts if debugging */
294 if (dev != kgdb_dev)
295 #endif
296 custom.intena = INTF_RBF|INTF_TBE; /* clear interrupt enable */
297 custom.intreq = INTF_RBF|INTF_TBE; /* and interrupt request */
298 #if 0
299 /* if the device is closed, it's close, no matter whether we deal with modem
300 control signals nor not. */
301 if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN ||
302 (tp->t_state&TS_ISOPEN) == 0)
303 #endif
304 (void) sermctl(dev, 0, DMSET);
305 ttyclose(tp);
306 #if 0
307 if (tp != &ser_cons)
308 {
309 remove_vbl_function (&ser_vbl_node[unit]);
310 ttyfree (tp);
311 ser_tty[unit] = (struct tty *)NULL;
312 }
313 #endif
314 return (0);
315 }
316
317 int
318 serread(dev, uio, flag)
319 dev_t dev;
320 struct uio *uio;
321 {
322 register struct tty *tp = ser_tty[SERUNIT(dev)];
323 int error;
324
325 if (! tp)
326 return ENXIO;
327
328 error = (*linesw[tp->t_line].l_read)(tp, uio, flag);
329
330 return error;
331 }
332
333 int
334 serwrite(dev, uio, flag)
335 dev_t dev;
336 struct uio *uio;
337 {
338 int unit = SERUNIT(dev);
339 register struct tty *tp = ser_tty[unit];
340
341 if (! tp)
342 return ENXIO;
343
344 /*
345 * (XXX) We disallow virtual consoles if the physical console is
346 * a serial port. This is in case there is a display attached that
347 * is not the console. In that situation we don't need/want the X
348 * server taking over the console.
349 */
350 if (constty && unit == serconsole)
351 constty = NULL;
352 return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
353 }
354
355
356 /* don't do any processing of data here, so we store the raw code
357 obtained from the uart register. In theory, 110kBaud gives you
358 11kcps, so 16k buffer should be more than enough, interrupt
359 latency of 1s should never happen, or something is seriously
360 wrong.. */
361 #define SERIBUF_SIZE 16384
362 static u_short serbuf[SERIBUF_SIZE];
363 static u_short *sbrpt = serbuf;
364 static u_short *sbwpt = serbuf;
365
366
367 /* this is a replacement for the lack of a hardware fifo. 32k should be
368 enough (there's only one unit anyway, so this is not going to
369 accumulate). */
370 void
371 ser_fastint ()
372 {
373 /* we're at RBE-level, which is higher than VBL-level which is used
374 to periodically transmit contents of this buffer up one layer,
375 so no spl-raising is necessary. */
376
377 register u_short ints, code;
378
379 ints = custom.intreqr & INTF_RBF;
380 if (! ints)
381 return;
382
383 /* clear interrupt */
384 custom.intreq = ints;
385 /* this register contains both data and status bits! */
386 code = custom.serdatr;
387
388 /* should really not happen, but you never know.. buffer
389 overflow. */
390 if (sbwpt + 1 == sbrpt
391 || (sbwpt == serbuf + SERIBUF_SIZE - 1 && sbrpt == serbuf))
392 {
393 log (LOG_WARNING, "ser_fastint: buffer overflow!");
394 return;
395 }
396
397 *sbwpt++ = code;
398 if (sbwpt == serbuf + SERIBUF_SIZE)
399 sbwpt = serbuf;
400 }
401
402
403 int
404 serintr (unit)
405 register int unit;
406 {
407 register struct serdevice *ser;
408 int s1, s2;
409
410 ser = ser_addr[unit];
411
412 /* make sure we're not interrupted by another
413 vbl, but allow level5 ints */
414 s1 = spltty();
415
416 /* ok, pass along any acumulated information .. */
417 while (sbrpt != sbwpt)
418 {
419 /* no collision with ser_fastint() */
420 sereint (unit, *sbrpt, ser);
421 /* lock against ser_fastint() */
422 s2 = spl5();
423 {
424 sbrpt++;
425 if (sbrpt == serbuf + SERIBUF_SIZE)
426 sbrpt = serbuf;
427 }
428 splx (s2);
429 }
430
431 splx (s1);
432
433 #if 0
434 /* add the code below if you really need it */
435 {
436 /*
437 * Process a received byte. Inline for speed...
438 */
439 #ifdef KGDB
440 #define RCVBYTE() \
441 ch = code & 0xff; \
442 if ((tp->t_state & TS_ISOPEN) == 0) { \
443 if (ch == FRAME_END && \
444 kgdb_dev == makedev(sermajor, unit)) \
445 kgdb_connect(0); /* trap into kgdb */ \
446 }
447 #else
448 #define RCVBYTE()
449 #endif
450 RCVBYTE();
451 /* sereint does the receive-processing */
452 sereint (unit, code, ser);
453 }
454 #endif
455 }
456
457 int
458 sereint(unit, stat, ser)
459 register int unit, stat;
460 register struct serdevice *ser;
461 {
462 register struct tty *tp;
463 register int c;
464 register u_char ch;
465
466 tp = ser_tty[unit];
467 if ((tp->t_state & TS_ISOPEN) == 0)
468 {
469 #ifdef KGDB
470 /* we don't care about parity errors */
471 if (kgdb_dev == makedev(sermajor, unit) && c == FRAME_END)
472 kgdb_connect(0); /* trap into kgdb */
473 #endif
474 return;
475 }
476
477 ch = stat & 0xff;
478 c = ch;
479 /* all databits 0 including stop indicate break condition */
480 if (!(stat & 0x1ff))
481 c |= TTY_FE;
482
483 /* if parity checking enabled, check parity */
484 else if ((tp->t_cflag & PARENB) &&
485 (((ch >> 7) + even_parity[ch & 0x7f] + !!(tp->t_cflag & PARODD)) & 1))
486 c |= TTY_PE;
487
488 if (stat & SERDATRF_OVRUN)
489 log(LOG_WARNING, "ser%d: silo overflow\n", unit);
490
491 (*linesw[tp->t_line].l_rint)(c, tp);
492 }
493
494 /* this interrupt is periodically invoked in the vertical blank
495 interrupt. It's used to keep track of the modem control lines
496 and (new with the fast_int code) to move accumulated data
497 up into the tty layer. */
498 void
499 sermint (register int unit)
500 {
501 register struct tty *tp;
502 register u_char stat, last, istat;
503 register struct serdevice *ser;
504
505 tp = ser_tty[unit];
506 if (!tp)
507 return;
508
509 if ((tp->t_state & (TS_ISOPEN|TS_WOPEN)) == 0)
510 {
511 sbrpt = sbwpt = serbuf;
512 return;
513 }
514
515 /* first empty buffer */
516 serintr (unit);
517
518 stat = ciab.pra;
519 last = last_ciab_pra;
520 last_ciab_pra = stat;
521
522 /* check whether any interesting signal changed state */
523 istat = stat ^ last;
524
525 if ((istat & CIAB_PRA_CD) && DIALIN(tp->t_dev))
526 {
527 if (ISDCD (stat))
528 (*linesw[tp->t_line].l_modem)(tp, 1);
529 else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
530 {
531 CLRDTR (stat);
532 CLRRTS (stat);
533 ciab.pra = stat;
534 last_ciab_pra = stat;
535 }
536 }
537 if ((istat & CIAB_PRA_CTS) && (tp->t_state & TS_ISOPEN) &&
538 (tp->t_cflag & CRTSCTS))
539 {
540 #if 0
541 /* the line is up and we want to do rts/cts flow control */
542 if (ISCTS (stat))
543 {
544 tp->t_state &=~ TS_TTSTOP;
545 ttstart(tp);
546 /* cause tbe-int if we were stuck there */
547 custom.intreq = INTF_SETCLR | INTF_TBE;
548 }
549 else
550 tp->t_state |= TS_TTSTOP;
551 #else
552 /* do this on hardware level, not with tty driver */
553 if (ISCTS (stat))
554 {
555 tp->t_state &= ~TS_TTSTOP;
556 /* cause TBE interrupt */
557 custom.intreq = INTF_SETCLR | INTF_TBE;
558 }
559 #endif
560 }
561 }
562
563 int
564 serioctl(dev, cmd, data, flag, p)
565 dev_t dev;
566 caddr_t data;
567 struct proc *p;
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, p);
579 if (error >= 0)
580 return (error);
581
582 error = ttioctl(tp, cmd, data, flag, p);
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