ser.c revision 1.2 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.2 1993/08/01 19:23:20 mycroft 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 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 struct tty *ser_tty[NSER] = { &ser_cons };
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 #if 0
134 #define UNIT(x) minor(x)
135 #else
136 /* just always force this to 0, so we can later interprete special
137 settings out of the unit number.. */
138 #define UNIT(x) 0
139 #endif
140
141 #ifdef DEBUG
142 long fifoin[17];
143 long fifoout[17];
144 long serintrcount[16];
145 long sermintcount[16];
146 #endif
147
148 serprobe(ad)
149 register struct amiga_device *ad;
150 {
151 register struct serdevice *ser;
152 register int unit;
153
154 ser = (struct serdevice *) ad->amiga_addr;
155 unit = ad->amiga_unit;
156 if (unit == serconsole)
157 DELAY(100000);
158
159 ad->amiga_ipl = 2;
160 ser_addr[unit] = ser;
161 ser_active |= 1 << unit;
162 sersoftCAR = ad->amiga_flags;
163 #ifdef KGDB
164 if (kgdb_dev == makedev(sermajor, unit)) {
165 if (serconsole == unit)
166 kgdb_dev = NODEV; /* can't debug over console port */
167 else {
168 (void) serinit(unit, kgdb_rate);
169 serconsinit = 1; /* don't re-init in serputc */
170 if (kgdb_debug_init) {
171 /*
172 * Print prefix of device name,
173 * let kgdb_connect print the rest.
174 */
175 printf("ser%d: ", unit);
176 kgdb_connect(1);
177 } else
178 printf("ser%d: kgdb enabled\n", unit);
179 }
180 }
181 #endif
182 /*
183 * Need to reset baud rate, etc. of next print so reset serconsinit.
184 * Also make sure console is always "hardwired."
185 */
186 if (unit == serconsole) {
187 serconsinit = 0;
188 sersoftCAR |= (1 << unit);
189 }
190 return (1);
191 }
192
193 /* ARGSUSED */
194 #ifdef __STDC__
195 seropen(dev_t dev, int flag, int mode, struct proc *p)
196 #else
197 seropen(dev, flag, mode, p)
198 dev_t dev;
199 int flag, mode;
200 struct proc *p;
201 #endif
202 {
203 register struct tty *tp;
204 register int unit;
205 int error = 0;
206
207 unit = minor (dev);
208
209 if (unit == 1)
210 {
211 unit = 0;
212 sersoftCAR = 0;
213 }
214 else if (unit == 2)
215 {
216 unit = 0;
217 sersoftCAR = 0xff;
218 }
219 else
220 unit = 0;
221
222 if (unit >= NSER || (ser_active & (1 << unit)) == 0)
223 return (ENXIO);
224 if(!ser_tty[unit]) {
225 MALLOC(tp, struct tty *, sizeof(struct tty), M_TTYS, M_WAITOK);
226 bzero(tp, sizeof(struct tty));
227 ser_tty[unit] = tp;
228 } else
229 tp = ser_tty[unit];
230 tp->t_oproc = serstart;
231 tp->t_param = serparam;
232 tp->t_dev = dev;
233 if ((tp->t_state & TS_ISOPEN) == 0) {
234 tp->t_state |= TS_WOPEN;
235 ttychars(tp);
236 if (tp->t_ispeed == 0) {
237 tp->t_iflag = TTYDEF_IFLAG | IXOFF; /* XXXXX */
238 tp->t_oflag = TTYDEF_OFLAG;
239 #if 0
240 tp->t_cflag = TTYDEF_CFLAG;
241 #else
242 tp->t_cflag = (CREAD | CS8 | CLOCAL); /* XXXXX */
243 #endif
244 tp->t_lflag = TTYDEF_LFLAG;
245 tp->t_ispeed = tp->t_ospeed = serdefaultrate;
246 }
247 serparam(tp, &tp->t_termios);
248 ttsetwater(tp);
249 } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
250 return (EBUSY);
251 (void) sermctl (dev, TIOCM_DTR | TIOCM_RTS, DMSET);
252 if ((sersoftCAR & (1 << unit)) || (sermctl(dev, 0, DMGET) & TIOCM_CD))
253 tp->t_state |= TS_CARR_ON;
254 (void) spltty();
255 while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 &&
256 (tp->t_state & TS_CARR_ON) == 0) {
257 tp->t_state |= TS_WOPEN;
258 if (error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH,
259 ttopen, 0))
260 break;
261 }
262 (void) spl0();
263 if (error == 0)
264 error = (*linesw[tp->t_line].l_open)(dev, tp);
265 return (error);
266 }
267
268 /*ARGSUSED*/
269 serclose(dev, flag, mode, p)
270 dev_t dev;
271 int flag, mode;
272 struct proc *p;
273 {
274 register struct tty *tp;
275 register struct serdevice *ser;
276 register int unit;
277
278 unit = UNIT(dev);
279
280 ser = ser_addr[unit];
281 tp = ser_tty[unit];
282 (*linesw[tp->t_line].l_close)(tp, flag);
283 custom.adkcon = ADKCONF_UARTBRK; /* clear break */
284 #ifdef KGDB
285 /* do not disable interrupts if debugging */
286 if (dev != kgdb_dev)
287 #endif
288 custom.intena = INTF_RBF | INTF_VERTB; /* clear interrupt enable */
289 custom.intreq = INTF_RBF | INTF_VERTB; /* and interrupt request */
290 #if 0
291 /* if the device is closed, it's close, no matter whether we deal with modem
292 control signals nor not. */
293 if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN ||
294 (tp->t_state&TS_ISOPEN) == 0)
295 #endif
296 (void) sermctl(dev, 0, DMSET);
297 ttyclose(tp);
298 #if 0
299 if (tp != &ser_cons)
300 {
301 FREE(tp, M_TTYS);
302 ser_tty[unit] = (struct tty *)NULL;
303 }
304 #endif
305 return (0);
306 }
307
308 serread(dev, uio, flag)
309 dev_t dev;
310 struct uio *uio;
311 {
312 register struct tty *tp = ser_tty[UNIT(dev)];
313 int error = (*linesw[tp->t_line].l_read)(tp, uio, flag);
314
315 return error;
316 }
317
318 serwrite(dev, uio, flag)
319 dev_t dev;
320 struct uio *uio;
321 {
322 int unit = UNIT(dev);
323 register struct tty *tp = ser_tty[unit];
324
325 /*
326 * (XXX) We disallow virtual consoles if the physical console is
327 * a serial port. This is in case there is a display attached that
328 * is not the console. In that situation we don't need/want the X
329 * server taking over the console.
330 */
331 if (constty && unit == serconsole)
332 constty = NULL;
333 return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
334 }
335
336 serintr(unit)
337 register int unit;
338 {
339 register struct serdevice *ser;
340 register u_short code;
341 register u_char ch;
342 register u_short ints;
343 register struct tty *tp;
344
345 ser = ser_addr[unit];
346
347 again:
348 ints = custom.intreqr & INTF_RBF;
349 if (! ints)
350 return 0;
351
352 /* clear interrupt(s) */
353 custom.intreq = ints;
354
355 /* this register contains both data and status bits! */
356 code = custom.serdatr;
357
358 if (ints & INTF_RBF)
359 {
360 tp = ser_tty[unit];
361 /*
362 * Process a received byte. Inline for speed...
363 */
364 #ifdef KGDB
365 #define RCVBYTE() \
366 ch = code & 0xff; \
367 if ((tp->t_state & TS_ISOPEN) == 0) { \
368 if (ch == FRAME_END && \
369 kgdb_dev == makedev(sermajor, unit)) \
370 kgdb_connect(0); /* trap into kgdb */ \
371 }
372 #else
373 #define RCVBYTE()
374 #endif
375 RCVBYTE();
376 /* sereint does the receive-processing */
377 sereint (unit, code, ser);
378 }
379
380 /* fake modem-control interrupt */
381 sermint (unit, ser);
382 /* try to save interrupt load.. */
383 goto again;
384 }
385
386 sereint(unit, stat, ser)
387 register int unit, stat;
388 register struct serdevice *ser;
389 {
390 register struct tty *tp;
391 register int c;
392 register u_char ch;
393
394 tp = ser_tty[unit];
395 if ((tp->t_state & TS_ISOPEN) == 0) {
396 #ifdef KGDB
397 /* we don't care about parity errors */
398 if (kgdb_dev == makedev(sermajor, unit) && c == FRAME_END)
399 kgdb_connect(0); /* trap into kgdb */
400 #endif
401 return;
402 }
403 ch = stat & 0xff;
404 c = ch;
405 /* all databits 0 including stop indicate break condition */
406 if (!(stat & 0x1ff))
407 c |= TTY_FE;
408
409 /* if parity checking enabled, check parity */
410 else if ((tp->t_cflag & PARENB) &&
411 (((ch >> 7) + even_parity[ch & 0x7f] + !!(tp->t_cflag & PARODD)) & 1))
412 c |= TTY_PE;
413
414 if (stat & SERDATRF_OVRUN)
415 log(LOG_WARNING, "ser%d: silo overflow\n", unit);
416
417 (*linesw[tp->t_line].l_rint)(c, tp);
418 }
419
420 sermint(unit)
421 register int unit;
422 {
423 register struct tty *tp;
424 register u_char stat, last, istat;
425 register struct serdevice *ser;
426
427 tp = ser_tty[unit];
428 stat = ciab.pra;
429 last = last_ciab_pra;
430 last_ciab_pra = stat;
431
432 /* check whether any interesting signal changed state */
433 istat = stat ^ last;
434
435 if ((istat & CIAB_PRA_CD) && (sersoftCAR & (1 << unit)) == 0)
436 {
437 if (ISDCD (stat))
438 (*linesw[tp->t_line].l_modem)(tp, 1);
439 else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
440 {
441 CLRDTR (stat);
442 CLRRTS (stat);
443 ciab.pra = stat;
444 last_ciab_pra = stat;
445 }
446 }
447 else if ((istat & CIAB_PRA_CTS) && (tp->t_state & TS_ISOPEN) &&
448 (tp->t_flags & CRTSCTS))
449 {
450 /* the line is up and we want to do rts/cts flow control */
451 if (ISCTS (stat))
452 {
453 tp->t_state &=~ TS_TTSTOP;
454 ttstart(tp);
455 }
456 else
457 tp->t_state |= TS_TTSTOP;
458 }
459 }
460
461 serioctl(dev, cmd, data, flag)
462 dev_t dev;
463 caddr_t data;
464 {
465 register struct tty *tp;
466 register int unit = UNIT(dev);
467 register struct serdevice *ser;
468 register int error;
469
470 tp = ser_tty[unit];
471 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
472 if (error >= 0)
473 return (error);
474 error = ttioctl(tp, cmd, data, flag);
475 if (error >= 0)
476 return (error);
477
478 ser = ser_addr[unit];
479 switch (cmd) {
480
481 case TIOCSBRK:
482 custom.adkcon = ADKCONF_SETCLR | ADKCONF_UARTBRK;
483 break;
484
485 case TIOCCBRK:
486 custom.adkcon = ADKCONF_UARTBRK;
487 break;
488
489 case TIOCSDTR:
490 (void) sermctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
491 break;
492
493 case TIOCCDTR:
494 (void) sermctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
495 break;
496
497 case TIOCMSET:
498 (void) sermctl(dev, *(int *)data, DMSET);
499 break;
500
501 case TIOCMBIS:
502 (void) sermctl(dev, *(int *)data, DMBIS);
503 break;
504
505 case TIOCMBIC:
506 (void) sermctl(dev, *(int *)data, DMBIC);
507 break;
508
509 case TIOCMGET:
510 *(int *)data = sermctl(dev, 0, DMGET);
511 break;
512
513 default:
514 return (ENOTTY);
515 }
516 return (0);
517 }
518
519 serparam(tp, t)
520 register struct tty *tp;
521 register struct termios *t;
522 {
523 register struct serdevice *ser;
524 register int cfcr, cflag = t->c_cflag;
525 int unit = UNIT(tp->t_dev);
526 int ospeed = ttspeedtab(t->c_ospeed, serspeedtab);
527
528 /* check requested parameters */
529 if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
530 return (EINVAL);
531 /* and copy to tty */
532 tp->t_ispeed = t->c_ispeed;
533 tp->t_ospeed = t->c_ospeed;
534 tp->t_cflag = cflag;
535
536 custom.intena = INTF_SETCLR | INTF_RBF;
537 custom.intreq = INTF_RBF;
538 last_ciab_pra = ciab.pra;
539
540 if (ospeed == 0) {
541 (void) sermctl(unit, 0, DMSET); /* hang up line */
542 return (0);
543 }
544 /* set the baud rate */
545 custom.serper = (0<<15) | ospeed; /* select 8 bit mode (instead of 9 bit) */
546
547 return (0);
548 }
549
550 serstart(tp)
551 register struct tty *tp;
552 {
553 register struct serdevice *ser;
554 int s, unit;
555 u_short c;
556
557 unit = UNIT(tp->t_dev);
558 ser = ser_addr[unit];
559 s = spltty();
560 again:
561 if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
562 goto out;
563 if (RB_LEN(&tp->t_out) <= tp->t_lowat) {
564 if (tp->t_state&TS_ASLEEP) {
565 tp->t_state &= ~TS_ASLEEP;
566 wakeup((caddr_t)&tp->t_out);
567 }
568 selwakeup (&tp->t_wsel);
569 }
570 if (RB_LEN(&tp->t_out) == 0)
571 goto out;
572
573 while (! (custom.serdatr & SERDATRF_TBE)) ;
574
575 c = rbgetc(&tp->t_out);
576 /* tp->t_state |= TS_BUSY; */
577
578 /* handle truncation of character if necessary */
579 if ((tp->t_cflag & CSIZE) == CS7)
580 c &= 0x7f;
581
582 /* handle parity if necessary (forces CS7) */
583 if (tp->t_cflag & PARENB)
584 {
585 if (even_parity[c & 0x7f])
586 c |= 0x80;
587 if (tp->t_cflag & PARODD)
588 c ^= 0x80;
589 }
590
591 /* add stop bit(s) */
592 if (tp->t_cflag & CSTOPB)
593 c |= 0x300;
594 else
595 c |= 0x100;
596
597 custom.serdat = c;
598
599 /* if there's input on the line, stop spitting out characters */
600 if (! (custom.intreqr & INTF_RBF))
601 goto again;
602
603 out:
604 splx(s);
605 }
606
607 /*
608 * Stop output on a line.
609 */
610 /*ARGSUSED*/
611 serstop(tp, flag)
612 register struct tty *tp;
613 {
614 register int s;
615
616 s = spltty();
617 if (tp->t_state & TS_BUSY) {
618 if ((tp->t_state&TS_TTSTOP)==0)
619 tp->t_state |= TS_FLUSH;
620 }
621 splx(s);
622 }
623
624 sermctl(dev, bits, how)
625 dev_t dev;
626 int bits, how;
627 {
628 register struct serdevice *ser;
629 register int unit;
630 u_char ub;
631 int s;
632
633 unit = UNIT(dev);
634 ser = ser_addr[unit];
635
636 /* convert TIOCM* mask into CIA mask (which is really low-active!!) */
637 if (how != DMGET)
638 {
639 ub = 0;
640 if (bits & TIOCM_DTR) ub |= CIAB_PRA_DTR;
641 if (bits & TIOCM_RTS) ub |= CIAB_PRA_RTS;
642 if (bits & TIOCM_CTS) ub |= CIAB_PRA_CTS;
643 if (bits & TIOCM_CD) ub |= CIAB_PRA_CD;
644 if (bits & TIOCM_RI) ub |= CIAB_PRA_SEL; /* collision with /dev/par ! */
645 if (bits & TIOCM_DSR) ub |= CIAB_PRA_DSR;
646 }
647
648
649 s = spltty();
650 switch (how) {
651
652 case DMSET:
653 /* invert and set */
654 ciab.pra = ~ub;
655 break;
656
657 case DMBIC:
658 ciab.pra |= ub;
659 ub = ~ciab.pra;
660 break;
661
662 case DMBIS:
663 ciab.pra &= ~ub;
664 ub = ~ciab.pra;
665 break;
666
667 case DMGET:
668 ub = ~ciab.pra;
669 break;
670 }
671 (void) splx(s);
672
673 bits = 0;
674 if (ub & CIAB_PRA_DTR) bits |= TIOCM_DTR;
675 if (ub & CIAB_PRA_RTS) bits |= TIOCM_RTS;
676 if (ub & CIAB_PRA_CTS) bits |= TIOCM_CTS;
677 if (ub & CIAB_PRA_CD) bits |= TIOCM_CD;
678 if (ub & CIAB_PRA_SEL) bits |= TIOCM_RI;
679 if (ub & CIAB_PRA_DSR) bits |= TIOCM_DSR;
680
681 return bits;
682 }
683
684 /*
685 * Following are all routines needed for SER to act as console
686 */
687 #include "../amiga/cons.h"
688
689 sercnprobe(cp)
690 struct consdev *cp;
691 {
692 int unit = CONUNIT;
693
694 /* locate the major number */
695 for (sermajor = 0; sermajor < nchrdev; sermajor++)
696 if (cdevsw[sermajor].d_open == seropen)
697 break;
698
699 /* XXX: ick */
700 unit = CONUNIT;
701
702 /* initialize required fields */
703 cp->cn_dev = makedev(sermajor, unit);
704 cp->cn_tp = ser_tty[unit];
705 cp->cn_pri = CN_NORMAL;
706
707 /*
708 * If serconsole is initialized, raise our priority.
709 */
710 if (serconsole == unit)
711 cp->cn_pri = CN_REMOTE;
712 #ifdef KGDB
713 if (major(kgdb_dev) == 1) /* XXX */
714 kgdb_dev = makedev(sermajor, minor(kgdb_dev));
715 #endif
716 }
717
718 sercninit(cp)
719 struct consdev *cp;
720 {
721 int unit = UNIT(cp->cn_dev);
722
723 serinit(unit, serdefaultrate);
724 serconsole = unit;
725 serconsinit = 1;
726 }
727
728 serinit(unit, rate)
729 int unit, rate;
730 {
731 int s;
732
733 #ifdef lint
734 stat = unit; if (stat) return;
735 #endif
736 s = splhigh();
737 /* might want to fiddle with the CIA later ??? */
738 custom.serper = ttspeedtab(rate, serspeedtab);
739 splx(s);
740 }
741
742 sercngetc(dev)
743 {
744 u_short stat;
745 int c, s;
746
747 #ifdef lint
748 stat = dev; if (stat) return (0);
749 #endif
750 s = splhigh();
751 while (!((stat = custom.serdatr & 0xffff) & SERDATRF_RBF))
752 ;
753 c = stat & 0xff;
754 /* clear interrupt */
755 custom.intreq = INTF_RBF;
756 splx(s);
757 return (c);
758 }
759
760 /*
761 * Console kernel output character routine.
762 */
763 sercnputc(dev, c)
764 dev_t dev;
765 register int c;
766 {
767 register int timo;
768 short stat;
769 int s = splhigh();
770
771 #ifdef lint
772 stat = dev; if (stat) return;
773 #endif
774 if (serconsinit == 0) {
775 (void) serinit(UNIT(dev), serdefaultrate);
776 serconsinit = 1;
777 }
778 /* wait for any pending transmission to finish */
779 timo = 50000;
780 while (! (custom.serdatr & SERDATRF_TBE) && --timo)
781 ;
782 custom.serdat = (c&0xff) | 0x100;
783 /* wait for this transmission to complete */
784 timo = 1500000;
785 while (! (custom.serdatr & SERDATRF_TBE) && --timo)
786 ;
787 /* wait for the device (my vt100..) to process the data, since
788 we don't do flow-control with cnputc */
789 for (timo = 0; timo < 30000; timo++) ;
790
791 /* clear any interrupts generated by this transmission */
792 custom.intreq = INTF_TBE;
793 splx(s);
794 }
795
796
797 serspit(c)
798 int c;
799 {
800 register struct Custom *cu asm("a2") = CUSTOMbase;
801 register int timo asm("d2");
802 extern int cold;
803 int s;
804
805 if (c == 10)
806 serspit (13);
807
808 s = splhigh();
809
810 /* wait for any pending transmission to finish */
811 timo = 500000;
812 while (! (cu->serdatr & (SERDATRF_TBE|SERDATRF_TSRE)) && --timo)
813 ;
814 cu->serdat = (c&0xff) | 0x100;
815 /* wait for this transmission to complete */
816 timo = 15000000;
817 while (! (cu->serdatr & SERDATRF_TBE) && --timo)
818 ;
819 /* clear any interrupts generated by this transmission */
820 cu->intreq = INTF_TBE;
821
822 for (timo = 0; timo < 30000; timo++) ;
823
824 splx (s);
825 }
826
827 int
828 serselect(dev, rw, p)
829 dev_t dev;
830 int rw;
831 struct proc *p;
832 {
833 register struct tty *tp = ser_tty[UNIT(dev)];
834 int nread;
835 int s = spltty();
836 struct proc *selp;
837
838 switch (rw) {
839
840 case FREAD:
841 nread = ttnread(tp);
842 if (nread > 0 ||
843 ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0))
844 goto win;
845 selrecord(p, &tp->t_rsel);
846 break;
847
848 case FWRITE:
849 if (RB_LEN(&tp->t_out) <= tp->t_lowat)
850 goto win;
851 selrecord(p, &tp->t_wsel);
852 break;
853 }
854 splx(s);
855 return (0);
856 win:
857 splx(s);
858 return (1);
859 }
860
861 #endif
862