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