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