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