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