ser.c revision 1.5 1 /* $NetBSD: ser.c,v 1.5 1998/07/04 22:18:22 jonathan Exp $ */
2
3 /*-
4 * Copyright (c) 1997 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Leo Weppelman.
9 *
10 * The driver structure is based on the i386 com-driver from Charles M. Hannum.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the NetBSD
23 * Foundation, Inc. and its contributors.
24 * 4. Neither the name of The NetBSD Foundation nor the names of its
25 * contributors may be used to endorse or promote products derived
26 * from this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 * POSSIBILITY OF SUCH DAMAGE.
39 */
40 #include "opt_ddb.h"
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/ioctl.h>
45 #include <sys/select.h>
46 #include <sys/tty.h>
47 #include <sys/proc.h>
48 #include <sys/user.h>
49 #include <sys/conf.h>
50 #include <sys/file.h>
51 #include <sys/uio.h>
52 #include <sys/kernel.h>
53 #include <sys/syslog.h>
54 #include <sys/types.h>
55 #include <sys/device.h>
56
57 #include <m68k/asm_single.h>
58
59 #include <machine/iomap.h>
60 #include <machine/mfp.h>
61 #include <atari/atari/intr.h>
62 #include <atari/dev/ym2149reg.h>
63 #include <atari/dev/serreg.h>
64
65 /* #define SER_DEBUG */
66
67 #define SERUNIT(x) (minor(x) & 0x7ffff)
68 #define SERDIALOUT(x) (minor(x) & 0x80000)
69
70 /* XXX */
71 #define CONSBAUD 9600
72 #define CONSCFLAG TTYDEF_CFLAG
73 /* end XXX */
74
75 /* Macros to clear/set/test flags. */
76 #define SET(t, f) (t) |= (f)
77 #define CLR(t, f) (t) &= ~(f)
78 #define ISSET(t, f) ((t) & (f))
79
80 #define splserial() spl6()
81
82 /* Buffer size for character buffer */
83 #define RXBUFSIZE 2048 /* More than enough.. */
84 #define RXBUFMASK (RXBUFSIZE-1) /* Only iff previous is a power of 2 */
85 #define RXHIWAT (RXBUFSIZE >> 2)
86
87 struct ser_softc {
88 struct device sc_dev;
89 struct tty *sc_tty;
90
91 int sc_overflows;
92 int sc_floods;
93 int sc_errors;
94
95 u_char sc_hwflags;
96 u_char sc_swflags;
97
98 int sc_ospeed; /* delay + timer-d data */
99 u_char sc_imra;
100 u_char sc_imrb;
101 u_char sc_ucr; /* Uart control */
102 u_char sc_msr; /* Modem status */
103 u_char sc_tsr; /* Tranceiver status */
104 u_char sc_rsr; /* Receiver status */
105 u_char sc_mcr; /* (Pseudo) Modem ctrl. */
106
107 u_char sc_msr_delta;
108 u_char sc_msr_mask;
109 u_char sc_mcr_active;
110 u_char sc_mcr_dtr, sc_mcr_rts, sc_msr_cts, sc_msr_dcd;
111
112 int sc_r_hiwat;
113 volatile u_int sc_rbget;
114 volatile u_int sc_rbput;
115 volatile u_int sc_rbavail;
116 u_char sc_rbuf[RXBUFSIZE];
117 u_char sc_lbuf[RXBUFSIZE];
118
119 volatile u_char sc_rx_blocked;
120 volatile u_char sc_rx_ready;
121 volatile u_char sc_tx_busy;
122 volatile u_char sc_tx_done;
123 volatile u_char sc_tx_stopped;
124 volatile u_char sc_st_check;
125
126 u_char *sc_tba;
127 int sc_tbc;
128 int sc_heldtbc;
129
130 volatile u_char sc_heldchange;
131 };
132
133 /*
134 * For sc_hwflags:
135 */
136 #define SER_HW_CONSOLE 0x01
137
138 cdev_decl(ser);
139
140 void ser_break __P((struct ser_softc *, int));
141 void ser_hwiflow __P((struct ser_softc *, int));
142 void ser_iflush __P((struct ser_softc *));
143 void ser_loadchannelregs __P((struct ser_softc *));
144 void ser_modem __P((struct ser_softc *, int));
145 void serdiag __P((void *));
146 int serhwiflow __P((struct tty *, int));
147 void serinit __P((int));
148 void serinitcons __P((int));
149 int baud;
150 int sermintr __P((void *));
151 int sertrintr __P((void *));
152 int serparam __P((struct tty *, struct termios *));
153 void serstart __P((struct tty *));
154
155 struct consdev;
156 void sercnprobe __P((struct consdev *));
157 void sercninit __P((struct consdev *));
158 int sercngetc __P((dev_t));
159 void sercnputc __P((dev_t, int));
160 void sercnpollc __P((dev_t, int));
161
162 static void sermsrint __P((struct ser_softc *, struct tty*));
163 static void serrxint __P((struct ser_softc *, struct tty*));
164 static void ser_shutdown __P((struct ser_softc *));
165 static int serspeed __P((long));
166 static void sersoft __P((void *));
167 static void sertxint __P((struct ser_softc *, struct tty*));
168
169 static volatile int ser_softintr_scheduled = 0;
170 static int sermajor;
171
172 /*
173 * Autoconfig stuff
174 */
175 static void serattach __P((struct device *, struct device *, void *));
176 static int sermatch __P((struct device *, struct cfdata *, void *));
177
178 struct cfattach ser_ca = {
179 sizeof(struct ser_softc), sermatch, serattach
180 };
181
182 extern struct cfdriver ser_cd;
183
184 /*ARGSUSED*/
185 static int
186 sermatch(pdp, cfp, auxp)
187 struct device *pdp;
188 struct cfdata *cfp;
189 void *auxp;
190 {
191 if (!strcmp((char *)auxp, "ser") && cfp->cf_unit == 0)
192 return (1);
193 return (0);
194 }
195
196 /*ARGSUSED*/
197 static void
198 serattach(pdp, dp, auxp)
199 struct device *pdp, *dp;
200 void *auxp;
201 {
202 struct ser_softc *sc = (void *)dp;
203
204 if (intr_establish(1, USER_VEC, 0, (hw_ifun_t)sermintr, sc) == NULL)
205 printf("serattach: Can't establish interrupt (1)\n");
206 if (intr_establish(2, USER_VEC, 0, (hw_ifun_t)sermintr, sc) == NULL)
207 printf("serattach: Can't establish interrupt (2)\n");
208 if (intr_establish(14, USER_VEC, 0, (hw_ifun_t)sermintr, sc) == NULL)
209 printf("serattach: Can't establish interrupt (14)\n");
210 if (intr_establish(9, USER_VEC, 0, (hw_ifun_t)sertrintr, sc) == NULL)
211 printf("serattach: Can't establish interrupt (9)\n");
212 if (intr_establish(10, USER_VEC, 0, (hw_ifun_t)sertrintr, sc) == NULL)
213 printf("serattach: Can't establish interrupt (10)\n");
214 if (intr_establish(11, USER_VEC, 0, (hw_ifun_t)sertrintr, sc) == NULL)
215 printf("serattach: Can't establish interrupt (11)\n");
216 if (intr_establish(12, USER_VEC, 0, (hw_ifun_t)sertrintr, sc) == NULL)
217 printf("serattach: Can't establish interrupt (12)\n");
218
219 ym2149_rts(1);
220 ym2149_dtr(1);
221
222 /*
223 * Enable but mask interrupts...
224 * XXX: Look at edge-sensitivity for DCD/CTS interrupts.
225 */
226 MFP->mf_ierb |= IB_SCTS|IB_SDCD;
227 MFP->mf_iera |= IA_RRDY|IA_RERR|IA_TRDY|IA_TERR;
228 MFP->mf_imrb &= ~(IB_SCTS|IB_SDCD);
229 MFP->mf_imra &= ~(IA_RRDY|IA_RERR|IA_TRDY|IA_TERR);
230
231 #ifdef SERCONSOLE
232 /*
233 * Activate serial console when DCD present...
234 */
235 if (!(MFP->mf_gpip & MCR_DCD))
236 SET(sc->sc_hwflags, SER_HW_CONSOLE);
237 #endif /* SERCONSOLE */
238
239 printf("\n");
240 if (ISSET(sc->sc_hwflags, SER_HW_CONSOLE)) {
241 serinit(CONSBAUD);
242 printf("%s: console\n", sc->sc_dev.dv_xname);
243 }
244 }
245
246 #ifdef SER_DEBUG
247 void serstatus __P((struct ser_softc *, char *));
248 void
249 serstatus(sc, str)
250 struct ser_softc *sc;
251 char *str;
252 {
253 struct tty *tp = sc->sc_tty;
254
255 printf("%s: %s %sclocal %sdcd %sts_carr_on %sdtr %stx_stopped\n",
256 sc->sc_dev.dv_xname, str,
257 ISSET(tp->t_cflag, CLOCAL) ? "+" : "-",
258 ISSET(sc->sc_msr, MCR_DCD) ? "+" : "-",
259 ISSET(tp->t_state, TS_CARR_ON) ? "+" : "-",
260 ISSET(sc->sc_mcr, MCR_DTR) ? "+" : "-",
261 sc->sc_tx_stopped ? "+" : "-");
262
263 printf("%s: %s %scrtscts %scts %sts_ttstop %srts %srx_blocked\n",
264 sc->sc_dev.dv_xname, str,
265 ISSET(tp->t_cflag, CRTSCTS) ? "+" : "-",
266 ISSET(sc->sc_msr, MCR_CTS) ? "+" : "-",
267 ISSET(tp->t_state, TS_TTSTOP) ? "+" : "-",
268 ISSET(sc->sc_mcr, MCR_RTS) ? "+" : "-",
269 sc->sc_rx_blocked ? "+" : "-");
270 }
271 #endif /* SER_DEBUG */
272
273 int
274 seropen(dev, flag, mode, p)
275 dev_t dev;
276 int flag, mode;
277 struct proc *p;
278 {
279 int unit = SERUNIT(dev);
280 struct ser_softc *sc;
281 struct tty *tp;
282 int s, s2;
283 int error = 0;
284
285 if (unit >= ser_cd.cd_ndevs)
286 return (ENXIO);
287 sc = ser_cd.cd_devs[unit];
288 if (!sc)
289 return (ENXIO);
290
291 if (!sc->sc_tty) {
292 tp = sc->sc_tty = ttymalloc();
293 tty_attach(tp);
294 } else
295 tp = sc->sc_tty;
296
297 if (ISSET(tp->t_state, TS_ISOPEN) &&
298 ISSET(tp->t_state, TS_XCLUDE) &&
299 p->p_ucred->cr_uid != 0)
300 return (EBUSY);
301
302 s = spltty();
303
304 /*
305 * Do the following if this is a first open.
306 */
307 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
308 struct termios t;
309
310 /* Turn on interrupts. */
311 sc->sc_imra = IA_RRDY|IA_RERR|IA_TRDY|IA_TERR;
312 sc->sc_imrb = IB_SCTS|IB_SDCD;
313 single_inst_bset_b(MFP->mf_imra, sc->sc_imra);
314 single_inst_bset_b(MFP->mf_imrb, sc->sc_imrb);
315
316 /* Fetch the current modem control status, needed later. */
317 sc->sc_msr = ~MFP->mf_gpip & (IO_SDCD|IO_SCTS|IO_SRI);
318
319 /* Add some entry points needed by the tty layer. */
320 tp->t_oproc = serstart;
321 tp->t_param = serparam;
322 tp->t_hwiflow = serhwiflow;
323 tp->t_dev = dev;
324
325 /*
326 * Initialize the termios status to the defaults. Add in the
327 * sticky bits from TIOCSFLAGS.
328 */
329 t.c_ispeed = 0;
330 if (ISSET(sc->sc_hwflags, SER_HW_CONSOLE)) {
331 t.c_ospeed = CONSBAUD;
332 t.c_cflag = CONSCFLAG;
333 }
334 else {
335 t.c_ospeed = TTYDEF_SPEED;
336 t.c_cflag = TTYDEF_CFLAG;
337 }
338 if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL))
339 SET(t.c_cflag, CLOCAL);
340 if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS))
341 SET(t.c_cflag, CRTSCTS);
342 if (ISSET(sc->sc_swflags, TIOCFLAG_MDMBUF))
343 SET(t.c_cflag, MDMBUF);
344 tp->t_iflag = TTYDEF_IFLAG;
345 tp->t_oflag = TTYDEF_OFLAG;
346 tp->t_lflag = TTYDEF_LFLAG;
347 ttychars(tp);
348 (void) serparam(tp, &t);
349 ttsetwater(tp);
350
351 s2 = splserial();
352
353 /*
354 * Turn on DTR. We must always do this, even if carrier is not
355 * present, because otherwise we'd have to use TIOCSDTR
356 * immediately after setting CLOCAL. We will drop DTR only on
357 * the next high-low transition of DCD, or by explicit request.
358 */
359 ser_modem(sc, 1);
360
361 /* Clear the input ring, and unblock. */
362 sc->sc_rbput = sc->sc_rbget = 0;
363 sc->sc_rbavail = RXBUFSIZE;
364 ser_iflush(sc);
365 sc->sc_rx_blocked = 0;
366 ser_hwiflow(sc, 0);
367
368 #ifdef SER_DEBUG
369 serstatus(sc, "seropen ");
370 #endif
371
372 splx(s2);
373 }
374
375 splx(s);
376
377 error = ttyopen(tp, SERDIALOUT(dev), ISSET(flag, O_NONBLOCK));
378 if (error)
379 goto bad;
380
381 error = (*linesw[tp->t_line].l_open)(dev, tp);
382 if (error)
383 goto bad;
384
385 return (0);
386
387 bad:
388 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
389 /*
390 * We failed to open the device, and nobody else had it opened.
391 * Clean up the state as appropriate.
392 */
393 ser_shutdown(sc);
394 }
395
396 return (error);
397 }
398
399 int
400 serclose(dev, flag, mode, p)
401 dev_t dev;
402 int flag, mode;
403 struct proc *p;
404 {
405 int unit = SERUNIT(dev);
406 struct ser_softc *sc = ser_cd.cd_devs[unit];
407 struct tty *tp = sc->sc_tty;
408
409 /* XXX This is for cons.c. */
410 if (!ISSET(tp->t_state, TS_ISOPEN))
411 return (0);
412
413 (*linesw[tp->t_line].l_close)(tp, flag);
414 ttyclose(tp);
415
416 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
417 /*
418 * Although we got a last close, the device may still be in
419 * use; e.g. if this was the dialout node, and there are still
420 * processes waiting for carrier on the non-dialout node.
421 */
422 ser_shutdown(sc);
423 }
424
425 return (0);
426 }
427
428 int
429 serread(dev, uio, flag)
430 dev_t dev;
431 struct uio *uio;
432 int flag;
433 {
434 struct ser_softc *sc = ser_cd.cd_devs[SERUNIT(dev)];
435 struct tty *tp = sc->sc_tty;
436
437 return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
438 }
439
440 int
441 serwrite(dev, uio, flag)
442 dev_t dev;
443 struct uio *uio;
444 int flag;
445 {
446 struct ser_softc *sc = ser_cd.cd_devs[SERUNIT(dev)];
447 struct tty *tp = sc->sc_tty;
448
449 return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
450 }
451
452 struct tty *
453 sertty(dev)
454 dev_t dev;
455 {
456 struct ser_softc *sc = ser_cd.cd_devs[SERUNIT(dev)];
457 struct tty *tp = sc->sc_tty;
458
459 return (tp);
460 }
461
462 int
463 serioctl(dev, cmd, data, flag, p)
464 dev_t dev;
465 u_long cmd;
466 caddr_t data;
467 int flag;
468 struct proc *p;
469 {
470 int unit = SERUNIT(dev);
471 struct ser_softc *sc = ser_cd.cd_devs[unit];
472 struct tty *tp = sc->sc_tty;
473 int error;
474
475 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
476 if (error >= 0)
477 return (error);
478
479 error = ttioctl(tp, cmd, data, flag, p);
480 if (error >= 0)
481 return (error);
482
483 switch (cmd) {
484 case TIOCSBRK:
485 ser_break(sc, 1);
486 break;
487
488 case TIOCCBRK:
489 ser_break(sc, 0);
490 break;
491
492 case TIOCSDTR:
493 ser_modem(sc, 1);
494 break;
495
496 case TIOCCDTR:
497 ser_modem(sc, 0);
498 break;
499
500 case TIOCGFLAGS:
501 *(int *)data = sc->sc_swflags;
502 break;
503
504 case TIOCSFLAGS:
505 error = suser(p->p_ucred, &p->p_acflag);
506 if (error)
507 return (error);
508 sc->sc_swflags = *(int *)data;
509 break;
510
511 case TIOCMSET:
512 case TIOCMBIS:
513 case TIOCMBIC:
514 case TIOCMGET:
515 default:
516 return (ENOTTY);
517 }
518
519 #ifdef SER_DEBUG
520 serstatus(sc, "serioctl ");
521 #endif
522
523 return (0);
524 }
525
526 void
527 ser_break(sc, onoff)
528 struct ser_softc *sc;
529 int onoff;
530 {
531 int s;
532
533 s = splserial();
534 if (onoff)
535 SET(sc->sc_tsr, TSR_SBREAK);
536 else
537 CLR(sc->sc_tsr, TSR_SBREAK);
538
539 if (!sc->sc_heldchange) {
540 if (sc->sc_tx_busy) {
541 sc->sc_heldtbc = sc->sc_tbc;
542 sc->sc_tbc = 0;
543 sc->sc_heldchange = 1;
544 } else
545 ser_loadchannelregs(sc);
546 }
547 splx(s);
548 }
549
550 void
551 ser_modem(sc, onoff)
552 struct ser_softc *sc;
553 int onoff;
554 {
555 int s;
556
557 s = splserial();
558 if (onoff)
559 SET(sc->sc_mcr, sc->sc_mcr_dtr);
560 else
561 CLR(sc->sc_mcr, sc->sc_mcr_dtr);
562
563 if (!sc->sc_heldchange) {
564 if (sc->sc_tx_busy) {
565 sc->sc_heldtbc = sc->sc_tbc;
566 sc->sc_tbc = 0;
567 sc->sc_heldchange = 1;
568 } else
569 ser_loadchannelregs(sc);
570 }
571 splx(s);
572 }
573
574 int
575 serparam(tp, t)
576 struct tty *tp;
577 struct termios *t;
578 {
579 struct ser_softc *sc = ser_cd.cd_devs[SERUNIT(tp->t_dev)];
580 int ospeed = serspeed(t->c_ospeed);
581 u_char ucr;
582 int s;
583
584 /* check requested parameters */
585 if (ospeed < 0)
586 return (EINVAL);
587 if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
588 return (EINVAL);
589
590 sc->sc_rsr = RSR_ENAB;
591 sc->sc_tsr = TSR_ENAB;
592
593 ucr = UCR_CLKDIV;
594
595 switch (ISSET(t->c_cflag, CSIZE)) {
596 case CS5:
597 SET(ucr, UCR_5BITS);
598 break;
599 case CS6:
600 SET(ucr, UCR_6BITS);
601 break;
602 case CS7:
603 SET(ucr, UCR_7BITS);
604 break;
605 case CS8:
606 SET(ucr, UCR_8BITS);
607 break;
608 }
609 if (ISSET(t->c_cflag, PARENB)) {
610 SET(ucr, UCR_PENAB);
611 if (!ISSET(t->c_cflag, PARODD))
612 SET(ucr, UCR_PEVEN);
613 }
614 if (ISSET(t->c_cflag, CSTOPB))
615 SET(ucr, UCR_STOPB2);
616 else
617 SET(ucr, UCR_STOPB1);
618
619 s = splserial();
620
621 sc->sc_ucr = ucr;
622
623 /*
624 * For the console, always force CLOCAL and !HUPCL, so that the port
625 * is always active.
626 */
627 if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR) ||
628 ISSET(sc->sc_hwflags, SER_HW_CONSOLE)) {
629 SET(t->c_cflag, CLOCAL);
630 CLR(t->c_cflag, HUPCL);
631 }
632
633 /*
634 * If we're not in a mode that assumes a connection is present, then
635 * ignore carrier changes.
636 */
637 if (ISSET(t->c_cflag, CLOCAL | MDMBUF))
638 sc->sc_msr_dcd = 0;
639 else
640 sc->sc_msr_dcd = MCR_DCD;
641 /*
642 * Set the flow control pins depending on the current flow control
643 * mode.
644 */
645 if (ISSET(t->c_cflag, CRTSCTS)) {
646 sc->sc_mcr_dtr = MCR_DTR;
647 sc->sc_mcr_rts = MCR_RTS;
648 sc->sc_msr_cts = MCR_CTS;
649 sc->sc_r_hiwat = RXHIWAT;
650 } else if (ISSET(t->c_cflag, MDMBUF)) {
651 /*
652 * For DTR/DCD flow control, make sure we don't toggle DTR for
653 * carrier detection.
654 */
655 sc->sc_mcr_dtr = 0;
656 sc->sc_mcr_rts = MCR_DTR;
657 sc->sc_msr_cts = MCR_DCD;
658 sc->sc_r_hiwat = RXHIWAT;
659 } else {
660 /*
661 * If no flow control, then always set RTS. This will make
662 * the other side happy if it mistakenly thinks we're doing
663 * RTS/CTS flow control.
664 */
665 sc->sc_mcr_dtr = MCR_DTR | MCR_RTS;
666 sc->sc_mcr_rts = 0;
667 sc->sc_msr_cts = 0;
668 sc->sc_r_hiwat = 0;
669 if (ISSET(sc->sc_mcr, MCR_DTR))
670 SET(sc->sc_mcr, MCR_RTS);
671 else
672 CLR(sc->sc_mcr, MCR_RTS);
673 }
674 sc->sc_msr_mask = sc->sc_msr_cts | sc->sc_msr_dcd;
675
676 #if 0
677 if (ospeed == 0)
678 CLR(sc->sc_mcr, sc->sc_mcr_dtr);
679 else
680 SET(sc->sc_mcr, sc->sc_mcr_dtr);
681 #endif
682
683 sc->sc_ospeed = ospeed;
684
685 /* and copy to tty */
686 tp->t_ispeed = 0;
687 tp->t_ospeed = t->c_ospeed;
688 tp->t_cflag = t->c_cflag;
689
690 if (!sc->sc_heldchange) {
691 if (sc->sc_tx_busy) {
692 sc->sc_heldtbc = sc->sc_tbc;
693 sc->sc_tbc = 0;
694 sc->sc_heldchange = 1;
695 } else
696 ser_loadchannelregs(sc);
697 }
698
699 splx(s);
700
701 /*
702 * Update the tty layer's idea of the carrier bit, in case we changed
703 * CLOCAL or MDMBUF. We don't hang up here; we only do that if we
704 * lose carrier while carrier detection is on.
705 */
706 (void) (*linesw[tp->t_line].l_modem)(tp, ISSET(sc->sc_msr, MCR_DCD));
707
708 #ifdef SER_DEBUG
709 serstatus(sc, "serparam ");
710 #endif
711
712 /* XXXXX FIX ME */
713 /* Block or unblock as needed. */
714 if (!ISSET(t->c_cflag, CHWFLOW)) {
715 if (sc->sc_rx_blocked) {
716 sc->sc_rx_blocked = 0;
717 ser_hwiflow(sc, 0);
718 }
719 if (sc->sc_tx_stopped) {
720 sc->sc_tx_stopped = 0;
721 serstart(tp);
722 }
723 } else {
724 #if 0
725 sermsrint(sc, tp);
726 #endif
727 }
728
729 return (0);
730 }
731
732 void
733 ser_iflush(sc)
734 struct ser_softc *sc;
735 {
736 u_char tmp;
737
738 /* flush any pending I/O */
739 while (ISSET(MFP->mf_rsr, RSR_CIP|RSR_BFULL))
740 tmp = MFP->mf_udr;
741 }
742
743 void
744 ser_loadchannelregs(sc)
745 struct ser_softc *sc;
746 {
747 /* XXXXX necessary? */
748 ser_iflush(sc);
749
750 /*
751 * No interrupts please...
752 */
753 if((MFP->mf_imra & (IA_RRDY|IA_RERR|IA_TRDY|IA_TERR)) != sc->sc_imra) {
754 printf("loadchannelregs: mf_imra: %x sc_imra: %x\n", (u_int)MFP->mf_imra,
755 (u_int)sc->sc_imra);
756 }
757 if((MFP->mf_imrb & (IB_SCTS|IB_SDCD)) != sc->sc_imrb) {
758 printf("loadchannelregs: mf_imrb: %x sc_imrb: %x\n", (u_int)MFP->mf_imrb,
759 (u_int)sc->sc_imrb);
760 }
761 single_inst_bclr_b(MFP->mf_imra, IA_RRDY|IA_RERR|IA_TRDY|IA_TERR);
762 single_inst_bclr_b(MFP->mf_imrb, IB_SCTS|IB_SDCD);
763
764 MFP->mf_ucr = sc->sc_ucr;
765 MFP->mf_rsr = sc->sc_rsr;
766 MFP->mf_tsr = sc->sc_tsr;
767
768 single_inst_bclr_b(MFP->mf_tcdcr, 0x07);
769 MFP->mf_tddr = sc->sc_ospeed;
770 single_inst_bset_b(MFP->mf_tcdcr, (sc->sc_ospeed >> 8) & 0x0f);
771
772 sc->sc_mcr_active = sc->sc_mcr;
773
774 if (machineid & ATARI_HADES) {
775 /* PCB fault, wires exchanged..... */
776 ym2149_rts(!(sc->sc_mcr_active & MCR_DTR));
777 ym2149_dtr(!(sc->sc_mcr_active & MCR_RTS));
778 }
779 else {
780 ym2149_rts(!(sc->sc_mcr_active & MCR_RTS));
781 ym2149_dtr(!(sc->sc_mcr_active & MCR_DTR));
782 }
783
784 single_inst_bset_b(MFP->mf_imra, sc->sc_imra);
785 single_inst_bset_b(MFP->mf_imrb, sc->sc_imrb);
786 }
787
788 int
789 serhwiflow(tp, block)
790 struct tty *tp;
791 int block;
792 {
793 struct ser_softc *sc = ser_cd.cd_devs[SERUNIT(tp->t_dev)];
794 int s;
795
796 if (sc->sc_mcr_rts == 0)
797 return (0);
798
799 s = splserial();
800 if (block) {
801 /*
802 * The tty layer is asking us to block input.
803 * If we already did it, just return TRUE.
804 */
805 if (sc->sc_rx_blocked)
806 goto out;
807 sc->sc_rx_blocked = 1;
808 } else {
809 /*
810 * The tty layer is asking us to resume input.
811 * The input ring is always empty by now.
812 */
813 sc->sc_rx_blocked = 0;
814 }
815 ser_hwiflow(sc, block);
816 out:
817 splx(s);
818 return (1);
819 }
820
821 /*
822 * (un)block input via hw flowcontrol
823 */
824 void
825 ser_hwiflow(sc, block)
826 struct ser_softc *sc;
827 int block;
828 {
829 if (sc->sc_mcr_rts == 0)
830 return;
831
832 if (block) {
833 CLR(sc->sc_mcr, sc->sc_mcr_rts);
834 CLR(sc->sc_mcr_active, sc->sc_mcr_rts);
835 } else {
836 SET(sc->sc_mcr, sc->sc_mcr_rts);
837 SET(sc->sc_mcr_active, sc->sc_mcr_rts);
838 }
839 if (machineid & ATARI_HADES) {
840 /* PCB fault, wires exchanged..... */
841 ym2149_dtr(sc->sc_mcr_active & MCR_RTS);
842 }
843 else {
844 ym2149_rts(sc->sc_mcr_active & MCR_RTS);
845 }
846 }
847
848 void
849 serstart(tp)
850 struct tty *tp;
851 {
852 struct ser_softc *sc = ser_cd.cd_devs[SERUNIT(tp->t_dev)];
853 int s;
854
855 s = spltty();
856 if (ISSET(tp->t_state, TS_BUSY))
857 goto out;
858 if (ISSET(tp->t_state, TS_TIMEOUT | TS_TTSTOP))
859 goto stopped;
860
861 if (sc->sc_tx_stopped)
862 goto stopped;
863
864 if (tp->t_outq.c_cc <= tp->t_lowat) {
865 if (ISSET(tp->t_state, TS_ASLEEP)) {
866 CLR(tp->t_state, TS_ASLEEP);
867 wakeup(&tp->t_outq);
868 }
869 selwakeup(&tp->t_wsel);
870 if (tp->t_outq.c_cc == 0)
871 goto stopped;
872 }
873
874 /* Grab the first contiguous region of buffer space. */
875 {
876 u_char *tba;
877 int tbc;
878
879 tba = tp->t_outq.c_cf;
880 tbc = ndqb(&tp->t_outq, 0);
881
882 (void)splserial();
883
884 sc->sc_tba = tba;
885 sc->sc_tbc = tbc;
886 }
887
888 SET(tp->t_state, TS_BUSY);
889 sc->sc_tx_busy = 1;
890
891 /* Enable transmit completion interrupts if necessary. */
892 if (!ISSET(sc->sc_imra, IA_TRDY)) {
893 SET(sc->sc_imra, IA_TRDY|IA_TERR);
894 single_inst_bset_b(MFP->mf_imra, IA_TRDY|IA_TERR);
895 }
896
897 /* Output the first char */
898 MFP->mf_udr = *sc->sc_tba;
899 sc->sc_tbc --;
900 sc->sc_tba ++;
901
902 splx(s);
903 return;
904
905 stopped:
906 /* Disable transmit completion interrupts if necessary. */
907 if (ISSET(sc->sc_imra, IA_TRDY)) {
908 CLR(sc->sc_imra, IA_TRDY|IA_TERR);
909 single_inst_bclr_b(MFP->mf_imra, IA_TRDY|IA_TERR);
910 }
911 out:
912 splx(s);
913 return;
914 }
915
916 /*
917 * Stop output on a line.
918 */
919 void
920 serstop(tp, flag)
921 struct tty *tp;
922 int flag;
923 {
924 struct ser_softc *sc = ser_cd.cd_devs[SERUNIT(tp->t_dev)];
925 int s;
926
927 s = splserial();
928 if (ISSET(tp->t_state, TS_BUSY)) {
929 /* Stop transmitting at the next chunk. */
930 sc->sc_tbc = 0;
931 sc->sc_heldtbc = 0;
932 if (!ISSET(tp->t_state, TS_TTSTOP))
933 SET(tp->t_state, TS_FLUSH);
934 }
935 splx(s);
936 }
937
938 void
939 serdiag(arg)
940 void *arg;
941 {
942 struct ser_softc *sc = arg;
943 int overflows, floods;
944 int s;
945
946 s = splserial();
947 overflows = sc->sc_overflows;
948 sc->sc_overflows = 0;
949 floods = sc->sc_floods;
950 sc->sc_floods = 0;
951 sc->sc_errors = 0;
952 splx(s);
953
954 log(LOG_WARNING,
955 "%s: %d silo overflow%s, %d ibuf flood%s\n",
956 sc->sc_dev.dv_xname,
957 overflows, overflows == 1 ? "" : "s",
958 floods, floods == 1 ? "" : "s");
959 }
960
961 static
962 void ser_shutdown(sc)
963 struct ser_softc *sc;
964 {
965 int s;
966 struct tty *tp = sc->sc_tty;
967
968
969 s = splserial();
970
971 /* If we were asserting flow control, then deassert it. */
972 sc->sc_rx_blocked = 1;
973 ser_hwiflow(sc, 1);
974
975 /* Clear any break condition set with TIOCSBRK. */
976 ser_break(sc, 0);
977
978 /*
979 * Hang up if necessary. Wait a bit, so the other side has time to
980 * notice even if we immediately open the port again.
981 */
982 if (ISSET(tp->t_cflag, HUPCL)) {
983 ser_modem(sc, 0);
984 (void) tsleep(sc, TTIPRI, ttclos, hz);
985 }
986
987 /* Turn off interrupts. */
988 CLR(sc->sc_imra, IA_RRDY|IA_RERR|IA_TRDY|IA_TERR);
989 CLR(sc->sc_imrb, IB_SCTS|IB_SDCD);
990 single_inst_bclr_b(MFP->mf_imrb, IB_SCTS|IB_SDCD);
991 single_inst_bclr_b(MFP->mf_imra, IA_RRDY|IA_RERR|IA_TRDY|IA_TERR);
992 splx(s);
993 }
994
995 static void
996 serrxint(sc, tp)
997 struct ser_softc *sc;
998 struct tty *tp;
999 {
1000 u_int get, cc, scc;
1001 int code;
1002 u_char rsr;
1003 int s;
1004 static int lsrmap[8] = {
1005 0, TTY_PE,
1006 TTY_FE, TTY_PE|TTY_FE,
1007 TTY_FE, TTY_PE|TTY_FE,
1008 TTY_FE, TTY_PE|TTY_FE
1009 };
1010
1011 get = sc->sc_rbget;
1012 scc = cc = RXBUFSIZE - sc->sc_rbavail;
1013
1014 if (cc == RXBUFSIZE) {
1015 sc->sc_floods++;
1016 if (sc->sc_errors++ == 0)
1017 timeout(serdiag, sc, 60 * hz);
1018 }
1019
1020 while (cc--) {
1021 rsr = sc->sc_lbuf[get];
1022 if (ISSET(rsr, RSR_BREAK)) {
1023 #ifdef DDB
1024 if (ISSET(sc->sc_hwflags, SER_HW_CONSOLE))
1025 Debugger();
1026 #endif
1027 }
1028 else if (ISSET(rsr, RSR_OERR)) {
1029 sc->sc_overflows++;
1030 if (sc->sc_errors++ == 0)
1031 timeout(serdiag, sc, 60 * hz);
1032 }
1033 code = sc->sc_rbuf[get] |
1034 lsrmap[(rsr & (RSR_BREAK|RSR_FERR|RSR_PERR)) >> 3];
1035 (*linesw[tp->t_line].l_rint)(code, tp);
1036 get = (get + 1) & RXBUFMASK;
1037 }
1038
1039 sc->sc_rbget = get;
1040 s = splserial();
1041 sc->sc_rbavail += scc;
1042 /*
1043 * Buffers should be ok again, release possible block, but only if the
1044 * tty layer isn't blocking too.
1045 */
1046 if (sc->sc_rx_blocked && !ISSET(tp->t_state, TS_TBLOCK)) {
1047 sc->sc_rx_blocked = 0;
1048 ser_hwiflow(sc, 0);
1049 }
1050 splx(s);
1051 }
1052
1053 static void
1054 sertxint(sc, tp)
1055 struct ser_softc *sc;
1056 struct tty *tp;
1057 {
1058
1059 CLR(tp->t_state, TS_BUSY);
1060 if (ISSET(tp->t_state, TS_FLUSH))
1061 CLR(tp->t_state, TS_FLUSH);
1062 else
1063 ndflush(&tp->t_outq, (int)(sc->sc_tba - tp->t_outq.c_cf));
1064 (*linesw[tp->t_line].l_start)(tp);
1065 }
1066
1067 static void
1068 sermsrint(sc, tp)
1069 struct ser_softc *sc;
1070 struct tty *tp;
1071 {
1072 u_char msr, delta;
1073 int s;
1074
1075 s = splserial();
1076 msr = sc->sc_msr;
1077 delta = sc->sc_msr_delta;
1078 sc->sc_msr_delta = 0;
1079 splx(s);
1080
1081 if (ISSET(delta, sc->sc_msr_dcd)) {
1082 /*
1083 * Inform the tty layer that carrier detect changed.
1084 */
1085 (void) (*linesw[tp->t_line].l_modem)(tp, ISSET(msr, MCR_DCD));
1086 }
1087
1088 if (ISSET(delta, sc->sc_msr_cts)) {
1089 /* Block or unblock output according to flow control. */
1090 if (ISSET(msr, sc->sc_msr_cts)) {
1091 sc->sc_tx_stopped = 0;
1092 (*linesw[tp->t_line].l_start)(tp);
1093 } else {
1094 sc->sc_tx_stopped = 1;
1095 serstop(tp, 0);
1096 }
1097 }
1098
1099 #ifdef SER_DEBUG
1100 serstatus(sc, "sermsrint");
1101 #endif
1102 }
1103
1104 void
1105 sersoft(arg)
1106 void *arg;
1107 {
1108 struct ser_softc *sc = arg;
1109 struct tty *tp;
1110
1111 ser_softintr_scheduled = 0;
1112
1113 tp = sc->sc_tty;
1114 if (tp == NULL)
1115 return;
1116
1117 if (!ISSET(tp->t_state, TS_ISOPEN) && (tp->t_wopen == 0))
1118 return;
1119
1120 if (sc->sc_rx_ready) {
1121 sc->sc_rx_ready = 0;
1122 serrxint(sc, tp);
1123 }
1124
1125 if (sc->sc_st_check) {
1126 sc->sc_st_check = 0;
1127 sermsrint(sc, tp);
1128 }
1129
1130 if (sc->sc_tx_done) {
1131 sc->sc_tx_done = 0;
1132 sertxint(sc, tp);
1133 }
1134 }
1135
1136 int
1137 sermintr(arg)
1138 void *arg;
1139 {
1140 struct ser_softc *sc = arg;
1141 u_char msr, delta;
1142
1143 msr = ~MFP->mf_gpip;
1144 delta = msr ^ sc->sc_msr;
1145 sc->sc_msr = sc->sc_msr & ~(MCR_CTS|MCR_DCD|MCR_RI);
1146 sc->sc_msr |= msr & (MCR_CTS|MCR_DCD|MCR_RI);
1147
1148 if (ISSET(delta, sc->sc_msr_mask)) {
1149 sc->sc_msr_delta |= delta;
1150
1151 /*
1152 * Stop output immediately if we lose the output
1153 * flow control signal or carrier detect.
1154 */
1155 if (ISSET(~msr, sc->sc_msr_mask)) {
1156 sc->sc_tbc = 0;
1157 sc->sc_heldtbc = 0;
1158 #ifdef SER_DEBUG
1159 serstatus(sc, "sermintr ");
1160 #endif
1161 }
1162
1163 sc->sc_st_check = 1;
1164 }
1165 if (!ser_softintr_scheduled)
1166 add_sicallback((si_farg)sersoft, sc, 0);
1167 return 1;
1168 }
1169
1170 int
1171 sertrintr(arg)
1172 void *arg;
1173 {
1174 struct ser_softc *sc = arg;
1175 u_int put, cc;
1176 u_char rsr, tsr;
1177
1178 put = sc->sc_rbput;
1179 cc = sc->sc_rbavail;
1180
1181 rsr = MFP->mf_rsr;
1182 if (ISSET(rsr, RSR_BFULL|RSR_BREAK)) {
1183 for (; ISSET(rsr, RSR_BFULL|RSR_BREAK) && cc > 0; cc--) {
1184 sc->sc_rbuf[put] = MFP->mf_udr;
1185 sc->sc_lbuf[put] = rsr;
1186 put = (put + 1) & RXBUFMASK;
1187 if ((rsr & RSR_BREAK) && (MFP->mf_rsr & RSR_BREAK))
1188 rsr = 0;
1189 else rsr = MFP->mf_rsr;
1190 }
1191 /*
1192 * Current string of incoming characters ended because
1193 * no more data was available. Schedule a receive event
1194 * if any data was received. Drop any characters that
1195 * we couldn't handle.
1196 */
1197 sc->sc_rbput = put;
1198 sc->sc_rbavail = cc;
1199 sc->sc_rx_ready = 1;
1200 /*
1201 * See if we are in danger of overflowing a buffer. If
1202 * so, use hardware flow control to ease the pressure.
1203 */
1204 if (sc->sc_rx_blocked == 0 &&
1205 cc < sc->sc_r_hiwat) {
1206 sc->sc_rx_blocked = 1;
1207 ser_hwiflow(sc, 1);
1208 }
1209 /*
1210 * If we're out of space, throw away any further input.
1211 */
1212 if (!cc) {
1213 while (ISSET(rsr, RSR_BFULL|RSR_BREAK)) {
1214 rsr = MFP->mf_udr;
1215 rsr = MFP->mf_rsr;
1216 }
1217 }
1218 }
1219
1220 /*
1221 * Done handling any receive interrupts. See if data can be
1222 * transmitted as well. Schedule tx done event if no data left
1223 * and tty was marked busy.
1224 */
1225 tsr = MFP->mf_tsr;
1226 if (ISSET(tsr, TSR_BE)) {
1227 /*
1228 * If we've delayed a parameter change, do it now, and restart
1229 * output.
1230 */
1231 if (sc->sc_heldchange) {
1232 ser_loadchannelregs(sc);
1233 sc->sc_heldchange = 0;
1234 sc->sc_tbc = sc->sc_heldtbc;
1235 sc->sc_heldtbc = 0;
1236 }
1237 /* Output the next character, if any. */
1238 if (sc->sc_tbc > 0) {
1239 MFP->mf_udr = *sc->sc_tba;
1240 sc->sc_tbc --;
1241 sc->sc_tba ++;
1242 } else if (sc->sc_tx_busy) {
1243 sc->sc_tx_busy = 0;
1244 sc->sc_tx_done = 1;
1245 }
1246 }
1247
1248 if (!ser_softintr_scheduled)
1249 add_sicallback((si_farg)sersoft, sc, 0);
1250 return 1;
1251 }
1252
1253 static int
1254 serspeed(speed)
1255 long speed;
1256 {
1257 #define divrnd(n, q) (((n)*2/(q)+1)/2) /* divide and round off */
1258
1259 int div, x, err;
1260
1261 if (speed <= 0)
1262 return (-1);
1263
1264 for (div = 4; div <= 64; div *= 4) {
1265 x = divrnd((SER_FREQ / div), speed);
1266
1267 /*
1268 * The value must fit in the timer-d dataregister. If
1269 * not, try another delay-mode.
1270 */
1271 if ((x/2) > 255)
1272 continue;
1273
1274 /*
1275 * Baudrate to high for the interface or cannot be made
1276 * within tolerance.
1277 */
1278 if (x <= 0)
1279 return (-1);
1280
1281 err = divrnd((SER_FREQ / div) * 1000, speed * x) - 1000;
1282 if (err < 0)
1283 err = -err;
1284 if (err > SER_TOLERANCE)
1285 continue;
1286
1287 /*
1288 * Translate 'div' to delay-code
1289 */
1290 if (div == 4)
1291 div = 1;
1292 else if (div == 16)
1293 div = 3;
1294 else if (div == 64)
1295 div = 5;
1296
1297 return ((x/2) | (div << 8));
1298 }
1299 return (-1);
1300
1301 #undef divrnd(n, q)
1302 }
1303
1304 /*
1305 * Following are all routines needed for SER to act as console
1306 */
1307 #include <dev/cons.h>
1308
1309 void
1310 sercnprobe(cp)
1311 struct consdev *cp;
1312 {
1313 /*
1314 * Activate serial console when DCD present...
1315 */
1316 if (MFP->mf_gpip & MCR_DCD) {
1317 cp->cn_pri = CN_DEAD;
1318 return;
1319 }
1320 for (sermajor = 0; sermajor < nchrdev; sermajor++)
1321 if (cdevsw[sermajor].d_open == seropen)
1322 break;
1323
1324 /* initialize required fields */
1325 cp->cn_dev = makedev(sermajor, 0); /* XXX: LWP What unit? */
1326 #ifdef SERCONSOLE
1327 cp->cn_pri = CN_REMOTE; /* Force a serial port console */
1328 #else
1329 cp->cn_pri = CN_NORMAL;
1330 #endif
1331 }
1332
1333 void
1334 sercninit(cp)
1335 struct consdev *cp;
1336 {
1337 serinitcons(CONSBAUD);
1338 }
1339
1340 /*
1341 * Initialize UART to known state.
1342 */
1343 void
1344 serinit(baud)
1345 int baud;
1346 {
1347 int ospeed = serspeed(baud);
1348
1349 MFP->mf_ucr = UCR_CLKDIV|UCR_8BITS|UCR_STOPB1;
1350 MFP->mf_rsr = RSR_ENAB;
1351 MFP->mf_tsr = TSR_ENAB;
1352
1353 single_inst_bclr_b(MFP->mf_tcdcr, 0x07);
1354 MFP->mf_tddr = ospeed;
1355 single_inst_bset_b(MFP->mf_tcdcr, (ospeed >> 8) & 0x0f);
1356 }
1357
1358 /*
1359 * Set UART for console use. Do normal init, then enable interrupts.
1360 */
1361 void
1362 serinitcons(baud)
1363 int baud;
1364 {
1365 serinit(baud);
1366
1367 /* Set rts/dtr */
1368 ym2149_rts(0);
1369 ym2149_dtr(0);
1370
1371 single_inst_bset_b(MFP->mf_imra, (IA_RRDY|IA_RERR|IA_TRDY|IA_TERR));
1372 }
1373
1374 int
1375 sercngetc(dev)
1376 dev_t dev;
1377 {
1378 u_char stat, c;
1379 int s;
1380
1381 s = splserial();
1382 while (!ISSET(stat = MFP->mf_rsr, RSR_BFULL)) {
1383 if (!ISSET(stat, RSR_ENAB)) /* XXX */
1384 MFP->mf_rsr |= RSR_ENAB;
1385 if (stat & (RSR_FERR|RSR_PERR|RSR_OERR))
1386 c = MFP->mf_udr;
1387 }
1388 c = MFP->mf_udr;
1389 splx(s);
1390 return c;
1391 }
1392
1393 u_int s_imra;
1394 u_int s_stat1, s_stat2, s_stat3;
1395 void
1396 sercnputc(dev, c)
1397 dev_t dev;
1398 int c;
1399 {
1400 int timo;
1401 u_char stat, imra;
1402
1403 /* Mask serial interrupts */
1404 imra = MFP->mf_imra & (IA_RRDY|IA_RERR|IA_TRDY|IA_TERR);
1405 single_inst_bclr_b(MFP->mf_imra, imra);
1406 s_imra = imra;
1407
1408 /* wait for any pending transmission to finish */
1409 timo = 50000;
1410 s_stat1 = MFP->mf_tsr;
1411 while (!ISSET(stat = MFP->mf_tsr, TSR_BE) && --timo)
1412 ;
1413 MFP->mf_udr = c;
1414 /* wait for this transmission to complete */
1415 timo = 1500000;
1416 s_stat2 = MFP->mf_tsr;
1417 while (!ISSET(stat = MFP->mf_tsr, TSR_BE) && --timo)
1418 ;
1419
1420 s_stat3 = MFP->mf_tsr;
1421 /* Clear pending serial interrupts and re-enable */
1422 single_inst_bclr_b(MFP->mf_ipra, imra);
1423 single_inst_bset_b(MFP->mf_imra, imra);
1424 }
1425
1426 void
1427 sercnpollc(dev, on)
1428 dev_t dev;
1429 int on;
1430 {
1431
1432 }
1433