xref: /netbsd-src/sys/arch/amiga/dev/ser.c (revision cda4f8f6ee55684e8d311b86c99ea59191e6b74f)
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