mfc.c revision 1.9 1 /* $NetBSD: mfc.c,v 1.9 1995/11/30 00:57:11 jtc Exp $ */
2
3 /*
4 * Copyright (c) 1994 Michael L. Hitch
5 * Copyright (c) 1982, 1990 The Regents of the University of California.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/device.h>
41 #include <sys/tty.h>
42 #include <sys/proc.h>
43 #include <sys/conf.h>
44 #include <sys/file.h>
45 #include <sys/malloc.h>
46 #include <sys/uio.h>
47 #include <sys/kernel.h>
48 #include <sys/syslog.h>
49 #include <sys/queue.h>
50 #include <machine/cpu.h>
51 #include <amiga/amiga/device.h>
52 #include <amiga/amiga/isr.h>
53 #include <amiga/amiga/custom.h>
54 #include <amiga/amiga/cia.h>
55 #include <amiga/amiga/cc.h>
56 #include <amiga/dev/zbusvar.h>
57
58 #include <dev/cons.h>
59
60 #include "mfcs.h"
61
62 #ifndef SEROBUF_SIZE
63 #define SEROBUF_SIZE 128
64 #endif
65 #ifndef SERIBUF_SIZE
66 #define SERIBUF_SIZE 1024
67 #endif
68
69 #define splser() spl6()
70
71 /*
72 * 68581 DUART registers
73 */
74 struct mfc_regs {
75 volatile u_char du_mr1a;
76 #define du_mr2a du_mr1a
77 u_char pad0;
78 volatile u_char du_csra;
79 #define du_sra du_csra
80 u_char pad2;
81 volatile u_char du_cra;
82 u_char pad4;
83 volatile u_char du_tba;
84 #define du_rba du_tba
85 u_char pad6;
86 volatile u_char du_acr;
87 #define du_ipcr du_acr
88 u_char pad8;
89 volatile u_char du_imr;
90 #define du_isr du_imr
91 u_char pad10;
92 volatile u_char du_ctur;
93 #define du_cmsb du_ctur
94 u_char pad12;
95 volatile u_char du_ctlr;
96 #define du_clsb du_ctlr
97 u_char pad14;
98 volatile u_char du_mr1b;
99 #define du_mr2b du_mr1b
100 u_char pad16;
101 volatile u_char du_csrb;
102 #define du_srb du_csrb
103 u_char pad18;
104 volatile u_char du_crb;
105 u_char pad20;
106 volatile u_char du_tbb;
107 #define du_rbb du_tbb
108 u_char pad22;
109 volatile u_char du_ivr;
110 u_char pad24;
111 volatile u_char du_opcr;
112 #define du_ip du_opcr
113 u_char pad26;
114 volatile u_char du_btst;
115 #define du_strc du_btst
116 u_char pad28;
117 volatile u_char du_btrst;
118 #define du_stpc du_btrst
119 u_char pad30;
120 };
121
122 /*
123 * 68681 DUART serial port registers
124 */
125 struct duart_regs {
126 volatile u_char ch_mr1;
127 #define ch_mr2 ch_mr1
128 u_char pad0;
129 volatile u_char ch_csr;
130 #define ch_sr ch_csr
131 u_char pad1;
132 volatile u_char ch_cr;
133 u_char pad2;
134 volatile u_char ch_tb;
135 #define ch_rb ch_tb
136 u_char pad3;
137 };
138
139 struct mfc_softc {
140 struct device sc_dev;
141 struct isr sc_isr;
142 struct mfc_regs *sc_regs;
143 u_long clk_frq;
144 u_short ct_val;
145 u_char ct_usecnt;
146 u_char imask;
147 u_char mfc_iii;
148 u_char last_ip;
149 };
150
151 #if NMFCS > 0
152 struct mfcs_softc {
153 struct device sc_dev;
154 struct tty *sc_tty;
155 struct duart_regs *sc_duart;
156 struct mfc_regs *sc_regs;
157 struct mfc_softc *sc_mfc;
158 int swflags;
159 long flags; /* XXX */
160 #define CT_USED 1 /* CT in use */
161 u_short *rptr, *wptr, incnt, ovfl;
162 u_short inbuf[SERIBUF_SIZE];
163 char *ptr, *end;
164 char outbuf[SEROBUF_SIZE];
165 struct vbl_node vbl_node;
166 };
167 #endif
168
169 #if NMFCP > 0
170 struct mfcp_softc {
171 };
172 #endif
173
174 struct mfc_args {
175 struct zbus_args zargs;
176 char *subdev;
177 char unit;
178 };
179
180 int mfcprint __P((void *auxp, char *));
181 void mfcattach __P((struct device *, struct device *, void *));
182 int mfcmatch __P((struct device *, struct cfdata *, void *));
183 #if NMFCS > 0
184 void mfcsattach __P((struct device *, struct device *, void *));
185 int mfcsmatch __P((struct device *, struct cfdata *, void *));
186 #endif
187 #if NMFCP > 0
188 void mfcpattach __P((struct device *, struct device *, void *));
189 int mfcpmatch __P((struct device *, struct cfdata *, void *));
190 #endif
191 int mfcintr __P((struct mfc_softc *));
192 void mfcsmint __P((register int unit));
193
194 struct cfdriver mfccd = {
195 NULL, "mfc", (cfmatch_t) mfcmatch, mfcattach,
196 DV_DULL, sizeof(struct mfc_softc), NULL, 0 };
197
198 #if NMFCS > 0
199 struct cfdriver mfcscd = {
200 NULL, "mfcs", (cfmatch_t) mfcsmatch, mfcsattach,
201 DV_TTY, sizeof(struct mfcs_softc), NULL, 0 };
202 #endif
203
204 #if NMFCP > 0
205 struct cfdriver mfcpcd = {
206 NULL, "mfcp", (cfmatch_t) mfcpmatch, mfcpattach,
207 DV_DULL, sizeof(struct mfcp_softc), NULL, 0 };
208 #endif
209
210 int mfcsstart(), mfcsparam(), mfcshwiflow();
211 int mfcs_active;
212 int mfcsdefaultrate = 38400 /*TTYDEF_SPEED*/;
213 #define SWFLAGS(dev) (sc->swflags | (((dev) & 0x80) == 0 ? TIOCFLAG_SOFTCAR : 0))
214
215 #ifdef notyet
216 /*
217 * MultiFaceCard III, II+ (not supported yet), and
218 * SerialMaster 500+ (not supported yet)
219 * baud rate tables for BRG set 1 [not used yet]
220 */
221
222 struct speedtab mfcs3speedtab1[] = {
223 0, 0,
224 100, 0x00,
225 220, 0x11,
226 600, 0x44,
227 1200, 0x55,
228 2400, 0x66,
229 4800, 0x88,
230 9600, 0x99,
231 19200, 0xbb,
232 115200, 0xcc,
233 -1, -1
234 };
235
236 /*
237 * MultiFaceCard II, I, and SerialMaster 500
238 * baud rate tables for BRG set 1 [not used yet]
239 */
240
241 struct speedtab mfcs2speedtab1[] = {
242 0, 0,
243 50, 0x00,
244 110, 0x11,
245 300, 0x44,
246 600, 0x55,
247 1200, 0x66,
248 2400, 0x88,
249 4800, 0x99,
250 9600, 0xbb,
251 38400, 0xcc,
252 -1, -1
253 };
254 #endif
255
256 /*
257 * MultiFaceCard III, II+ (not supported yet), and
258 * SerialMaster 500+ (not supported yet)
259 * baud rate tables for BRG set 2
260 */
261
262 struct speedtab mfcs3speedtab2[] = {
263 0, 0,
264 150, 0x00,
265 200, 0x11,
266 300, 0x33,
267 600, 0x44,
268 1200, 0x55,
269 2400, 0x66,
270 4800, 0x88,
271 9600, 0x99,
272 19200, 0xbb,
273 38400, 0xcc,
274 -1, -1
275 };
276
277 /*
278 * MultiFaceCard II, I, and SerialMaster 500
279 * baud rate tables for BRG set 2
280 */
281
282 struct speedtab mfcs2speedtab2[] = {
283 0, 0,
284 75, 0x00,
285 100, 0x11,
286 150, 0x33,
287 300, 0x44,
288 600, 0x55,
289 1200, 0x66,
290 2400, 0x88,
291 4800, 0x99,
292 9600, 0xbb,
293 19200, 0xcc,
294 -1, -1
295 };
296
297 /*
298 * if we are an bsc/Alf Data MultFaceCard (I, II, and III)
299 */
300 int
301 mfcmatch(pdp, cdp, auxp)
302 struct device *pdp;
303 struct cfdata *cdp;
304 void *auxp;
305 {
306 struct zbus_args *zap;
307
308 zap = auxp;
309 if (zap->manid == 2092 &&
310 (zap->prodid == 16 || zap->prodid == 17 || zap->prodid == 18))
311
312 return(1);
313 return(0);
314 }
315
316 void
317 mfcattach(pdp, dp, auxp)
318 struct device *pdp, *dp;
319 void *auxp;
320 {
321 struct mfc_softc *scc;
322 struct zbus_args *zap;
323 struct mfc_args ma;
324 int unit;
325 struct mfc_regs *rp;
326
327 zap = auxp;
328
329 printf ("\n");
330
331 scc = (struct mfc_softc *)dp;
332 unit = scc->sc_dev.dv_unit;
333 scc->sc_regs = rp = zap->va;
334 if (zap->prodid == 18)
335 scc->mfc_iii = 3;
336 scc->clk_frq = scc->mfc_iii ? 230400 : 115200;
337
338 rp->du_opcr = 0x00; /* configure output port? */
339 rp->du_btrst = 0x0f; /* clear modem lines */
340 rp->du_ivr = 0; /* IVR */
341 rp->du_imr = 0; /* IMR */
342 rp->du_acr = 0xe0; /* baud rate generate set 2 */
343 rp->du_ctur = 0;
344 rp->du_ctlr = 4;
345 rp->du_csra = 0xcc; /* clock select = 38400 */
346 rp->du_cra = 0x10; /* reset mode register ptr */
347 rp->du_cra = 0x20;
348 rp->du_cra = 0x30;
349 rp->du_cra = 0x40;
350 rp->du_mr1a = 0x93; /* MRA1 */
351 rp->du_mr2a = 0x17; /* MRA2 */
352 rp->du_csrb = 0xcc; /* clock select = 38400 */
353 rp->du_crb = 0x10; /* reset mode register ptr */
354 rp->du_crb = 0x20;
355 rp->du_crb = 0x30;
356 rp->du_crb = 0x40;
357 rp->du_mr1b = 0x93; /* MRB1 */
358 rp->du_mr2b = 0x17; /* MRB2 */
359 rp->du_cra = 0x05; /* enable A Rx & Tx */
360 rp->du_crb = 0x05; /* enable B Rx & Tx */
361
362 scc->sc_isr.isr_intr = mfcintr;
363 scc->sc_isr.isr_arg = scc;
364 scc->sc_isr.isr_ipl = 6;
365 add_isr(&scc->sc_isr);
366
367 /* configure ports */
368 bcopy(zap, &ma.zargs, sizeof(struct zbus_args));
369 ma.subdev = "mfcs";
370 ma.unit = unit * 2;
371 config_found(dp, &ma, mfcprint);
372 ma.unit = unit * 2 + 1;
373 config_found(dp, &ma, mfcprint);
374 ma.subdev = "mfcp";
375 ma.unit = unit;
376 config_found(dp, &ma, mfcprint);
377 }
378
379 /*
380 *
381 */
382 int
383 mfcsmatch(pdp, cdp, auxp)
384 struct device *pdp;
385 struct cfdata *cdp;
386 void *auxp;
387 {
388 struct mfc_args *ma;
389
390 ma = auxp;
391 if (strcmp(ma->subdev, "mfcs") == 0)
392 return (1);
393 return (0);
394 }
395
396 void
397 mfcsattach(pdp, dp, auxp)
398 struct device *pdp, *dp;
399 void *auxp;
400 {
401 int unit;
402 struct mfcs_softc *sc;
403 struct mfc_softc *scc;
404 struct mfc_args *ma;
405 struct mfc_regs *rp;
406
407 sc = (struct mfcs_softc *) dp;
408 scc = (struct mfc_softc *) pdp;
409 ma = auxp;
410
411 if (dp) {
412 printf (": input fifo %d output fifo %d\n", SERIBUF_SIZE,
413 SEROBUF_SIZE);
414 alloc_sicallback();
415 }
416
417 unit = ma->unit;
418 mfcs_active |= 1 << unit;
419 sc->rptr = sc->wptr = sc->inbuf;
420 sc->sc_mfc = scc;
421 sc->sc_regs = rp = scc->sc_regs;
422 sc->sc_duart = (struct duart_regs *) ((unit & 1) ? &rp->du_mr1b :
423 &rp->du_mr1a);
424 /*
425 * should have only one vbl routine to handle all ports?
426 */
427 sc->vbl_node.function = (void (*) (void *)) mfcsmint;
428 sc->vbl_node.data = (void *) unit;
429 add_vbl_function(&sc->vbl_node, 1, (void *) unit);
430 }
431
432 /*
433 * print diag if pnp is NULL else just extra
434 */
435 int
436 mfcprint(auxp, pnp)
437 void *auxp;
438 char *pnp;
439 {
440 if (pnp == NULL)
441 return(UNCONF);
442 return(QUIET);
443 }
444
445 int
446 mfcsopen(dev, flag, mode, p)
447 dev_t dev;
448 int flag, mode;
449 struct proc *p;
450 {
451 struct tty *tp;
452 struct mfcs_softc *sc;
453 int unit, error, s;
454
455 error = 0;
456 unit = dev & 0x1f;
457
458 if (unit >= mfcscd.cd_ndevs || (mfcs_active & (1 << unit)) == 0)
459 return (ENXIO);
460 sc = mfcscd.cd_devs[unit];
461
462 s = spltty();
463
464 if (sc->sc_tty)
465 tp = sc->sc_tty;
466 else
467 tp = sc->sc_tty = ttymalloc();
468
469 tp->t_oproc = (void (*) (struct tty *)) mfcsstart;
470 tp->t_param = mfcsparam;
471 tp->t_dev = dev;
472 tp->t_hwiflow = mfcshwiflow;
473
474 if ((tp->t_state & TS_ISOPEN) == 0) {
475 tp->t_state |= TS_WOPEN;
476 ttychars(tp);
477 if (tp->t_ispeed == 0) {
478 /*
479 * only when cleared do we reset to defaults.
480 */
481 tp->t_iflag = TTYDEF_IFLAG;
482 tp->t_oflag = TTYDEF_OFLAG;
483 tp->t_cflag = TTYDEF_CFLAG;
484 tp->t_lflag = TTYDEF_LFLAG;
485 tp->t_ispeed = tp->t_ospeed = mfcsdefaultrate;
486 }
487 /*
488 * do these all the time
489 */
490 if (sc->swflags & TIOCFLAG_CLOCAL)
491 tp->t_cflag |= CLOCAL;
492 if (sc->swflags & TIOCFLAG_CRTSCTS)
493 tp->t_cflag |= CRTSCTS;
494 if (sc->swflags & TIOCFLAG_MDMBUF)
495 tp->t_cflag |= MDMBUF;
496 mfcsparam(tp, &tp->t_termios);
497 ttsetwater(tp);
498
499 (void)mfcsmctl(dev, TIOCM_DTR | TIOCM_RTS, DMSET);
500 if ((SWFLAGS(dev) & TIOCFLAG_SOFTCAR) ||
501 (mfcsmctl(dev, 0, DMGET) & TIOCM_CD))
502 tp->t_state |= TS_CARR_ON;
503 else
504 tp->t_state &= ~TS_CARR_ON;
505 } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
506 splx(s);
507 return(EBUSY);
508 }
509
510 /*
511 * if NONBLOCK requested, ignore carrier
512 */
513 if (flag & O_NONBLOCK)
514 goto done;
515
516 /*
517 * block waiting for carrier
518 */
519 while ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0) {
520 tp->t_state |= TS_WOPEN;
521 error = ttysleep(tp, (caddr_t)&tp->t_rawq,
522 TTIPRI | PCATCH, ttopen, 0);
523 if (error) {
524 splx(s);
525 return(error);
526 }
527 }
528 done:
529 /* This is a way to handle lost XON characters */
530 if ((flag & O_TRUNC) && (tp->t_state & TS_TTSTOP)) {
531 tp->t_state &= ~TS_TTSTOP;
532 ttstart (tp);
533 }
534
535 splx(s);
536 /*
537 * Reset the tty pointer, as there could have been a dialout
538 * use of the tty with a dialin open waiting.
539 */
540 tp->t_dev = dev;
541 return((*linesw[tp->t_line].l_open)(dev, tp));
542 }
543
544 /*ARGSUSED*/
545 int
546 mfcsclose(dev, flag, mode, p)
547 dev_t dev;
548 int flag, mode;
549 struct proc *p;
550 {
551 struct tty *tp;
552 int unit;
553 struct mfcs_softc *sc = mfcscd.cd_devs[dev & 31];
554 struct mfc_softc *scc= sc->sc_mfc;
555
556 unit = dev & 31;
557
558 tp = sc->sc_tty;
559 (*linesw[tp->t_line].l_close)(tp, flag);
560 sc->sc_duart->ch_cr = 0x70; /* stop break */
561
562 scc->imask &= ~(0x7 << ((unit & 1) * 4));
563 scc->sc_regs->du_imr = scc->imask;
564 if (sc->flags & CT_USED) {
565 --scc->ct_usecnt;
566 sc->flags &= ~CT_USED;
567 }
568
569 /*
570 * If the device is closed, it's close, no matter whether we deal with
571 * modem control signals nor not.
572 */
573 #if 0
574 if (tp->t_cflag & HUPCL || tp->t_state & TS_WOPEN ||
575 (tp->t_state & TS_ISOPEN) == 0)
576 #endif
577 (void) mfcsmctl(dev, 0, DMSET);
578 ttyclose(tp);
579 #if not_yet
580 if (tp != &mfcs_cons) {
581 remove_vbl_function(&sc->vbl_node);
582 ttyfree(tp);
583 sc->sc_tty = (struct tty *) NULL;
584 }
585 #endif
586 return (0);
587 }
588
589 int
590 mfcsread(dev, uio, flag)
591 dev_t dev;
592 struct uio *uio;
593 int flag;
594 {
595 struct mfcs_softc *sc = mfcscd.cd_devs[dev & 31];
596 struct tty *tp = sc->sc_tty;
597 if (tp == NULL)
598 return(ENXIO);
599 return((*linesw[tp->t_line].l_read)(tp, uio, flag));
600 }
601
602 int
603 mfcswrite(dev, uio, flag)
604 dev_t dev;
605 struct uio *uio;
606 int flag;
607 {
608 struct mfcs_softc *sc = mfcscd.cd_devs[dev & 31];
609 struct tty *tp = sc->sc_tty;
610
611 if (tp == NULL)
612 return(ENXIO);
613 return((*linesw[tp->t_line].l_write)(tp, uio, flag));
614 }
615
616 struct tty *
617 mfcstty(dev)
618 dev_t dev;
619 {
620 struct mfcs_softc *sc = mfcscd.cd_devs[dev & 31];
621
622 return (sc->sc_tty);
623 }
624
625 int
626 mfcsioctl(dev, cmd, data, flag, p)
627 dev_t dev;
628 caddr_t data;
629 struct proc *p;
630 {
631 register struct tty *tp;
632 register int unit = dev & 31;
633 register int error;
634 struct mfcs_softc *sc = mfcscd.cd_devs[dev & 31];
635
636 tp = sc->sc_tty;
637 if (!tp)
638 return ENXIO;
639
640 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
641 if (error >= 0)
642 return(error);
643
644 error = ttioctl(tp, cmd, data, flag, p);
645 if (error >= 0)
646 return(error);
647
648 switch (cmd) {
649 case TIOCSBRK:
650 sc->sc_duart->ch_cr = 0x60; /* start break */
651 break;
652
653 case TIOCCBRK:
654 sc->sc_duart->ch_cr = 0x70; /* stop break */
655 break;
656
657 case TIOCSDTR:
658 (void) mfcsmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
659 break;
660
661 case TIOCCDTR:
662 (void) mfcsmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
663 break;
664
665 case TIOCMSET:
666 (void) mfcsmctl(dev, *(int *) data, DMSET);
667 break;
668
669 case TIOCMBIS:
670 (void) mfcsmctl(dev, *(int *) data, DMBIS);
671 break;
672
673 case TIOCMBIC:
674 (void) mfcsmctl(dev, *(int *) data, DMBIC);
675 break;
676
677 case TIOCMGET:
678 *(int *)data = mfcsmctl(dev, 0, DMGET);
679 break;
680 case TIOCGFLAGS:
681 *(int *)data = SWFLAGS(dev);
682 break;
683 case TIOCSFLAGS:
684 error = suser(p->p_ucred, &p->p_acflag);
685 if (error != 0)
686 return(EPERM);
687
688 sc->swflags = *(int *)data;
689 sc->swflags &= /* only allow valid flags */
690 (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
691 /* XXXX need to change duart parameters? */
692 break;
693 default:
694 return(ENOTTY);
695 }
696
697 return(0);
698 }
699
700 int
701 mfcsparam(tp, t)
702 struct tty *tp;
703 struct termios *t;
704 {
705 int cfcr, cflag, unit, ospeed;
706 struct mfcs_softc *sc = mfcscd.cd_devs[tp->t_dev & 31];
707 struct mfc_softc *scc= sc->sc_mfc;
708
709 cflag = t->c_cflag;
710 unit = tp->t_dev & 31;
711 if (sc->flags & CT_USED) {
712 --scc->ct_usecnt;
713 sc->flags &= ~CT_USED;
714 }
715 ospeed = ttspeedtab(t->c_ospeed, scc->mfc_iii ? mfcs3speedtab2 :
716 mfcs2speedtab2);
717
718 /*
719 * If Baud Rate Generator can't generate requested speed,
720 * try to use the counter/timer.
721 */
722 if (ospeed < 0 && (scc->clk_frq % t->c_ospeed) == 0) {
723 ospeed = scc->clk_frq / t->c_ospeed; /* divisor */
724 if (scc->ct_usecnt > 0 && scc->ct_val != ospeed)
725 ospeed = -1;
726 else {
727 scc->sc_regs->du_ctur = ospeed >> 8;
728 scc->sc_regs->du_ctlr = ospeed;
729 scc->ct_val = ospeed;
730 ++scc->ct_usecnt;
731 sc->flags |= CT_USED;
732 ospeed = 0xdd;
733 }
734 }
735 /* XXXX 68681 duart could handle split speeds */
736 if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
737 return(EINVAL);
738
739 /* XXXX handle parity, character size, stop bits, flow control */
740
741 /*
742 * copy to tty
743 */
744 tp->t_ispeed = t->c_ispeed;
745 tp->t_ospeed = t->c_ospeed;
746 tp->t_cflag = cflag;
747
748 /*
749 * enable interrupts
750 */
751 scc->imask |= (0x2 << ((unit & 1) * 4)) | 0x80;
752 scc->sc_regs->du_imr = scc->imask;
753 #if defined(DEBUG) && 0
754 printf("mfcsparam: speed %d => %x ct %d imask %x cflag %x\n",
755 t->c_ospeed, ospeed, scc->ct_val, scc->imask, cflag);
756 #endif
757 if (ospeed == 0)
758 (void)mfcsmctl(tp->t_dev, 0, DMSET); /* hang up line */
759 else {
760 /*
761 * (re)enable DTR
762 * and set baud rate. (8 bit mode)
763 */
764 (void)mfcsmctl(tp->t_dev, TIOCM_DTR | TIOCM_RTS, DMSET);
765 sc->sc_duart->ch_csr = ospeed;
766 }
767 return(0);
768 }
769
770 int mfcshwiflow(tp, flag)
771 struct tty *tp;
772 int flag;
773 {
774 struct mfcs_softc *sc = mfcscd.cd_devs[tp->t_dev & 31];
775 int unit = tp->t_dev & 1;
776
777 if (flag)
778 sc->sc_regs->du_btrst = 1 << unit;
779 else
780 sc->sc_regs->du_btst = 1 << unit;
781 return 1;
782 }
783
784 int
785 mfcsstart(tp)
786 struct tty *tp;
787 {
788 int cc, s, unit;
789 struct mfcs_softc *sc = mfcscd.cd_devs[tp->t_dev & 31];
790 struct mfc_softc *scc= sc->sc_mfc;
791
792 if ((tp->t_state & TS_ISOPEN) == 0)
793 return;
794
795 unit = tp->t_dev & 1;
796
797 s = splser();
798 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
799 goto out;
800
801 cc = tp->t_outq.c_cc;
802 if (cc <= tp->t_lowat) {
803 if (tp->t_state & TS_ASLEEP) {
804 tp->t_state &= ~TS_ASLEEP;
805 wakeup((caddr_t) & tp->t_outq);
806 }
807 selwakeup(&tp->t_wsel);
808 }
809 if (cc == 0 || (tp->t_state & TS_BUSY))
810 goto out;
811
812 /*
813 * We only do bulk transfers if using CTSRTS flow control, not for
814 * (probably sloooow) ixon/ixoff devices.
815 */
816 if ((tp->t_cflag & CRTSCTS) == 0)
817 cc = 1;
818
819 /*
820 * Limit the amount of output we do in one burst
821 * to prevent hogging the CPU.
822 */
823 if (cc > SEROBUF_SIZE)
824 cc = SEROBUF_SIZE;
825 cc = q_to_b(&tp->t_outq, sc->outbuf, cc);
826 if (cc > 0) {
827 tp->t_state |= TS_BUSY;
828
829 sc->ptr = sc->outbuf;
830 sc->end = sc->outbuf + cc;
831
832 /*
833 * Get first character out, then have TBE-interrupts blow out
834 * further characters, until buffer is empty, and TS_BUSY gets
835 * cleared.
836 */
837 sc->sc_duart->ch_tb = *sc->ptr++;
838 scc->imask |= 1 << (unit * 4);
839 sc->sc_regs->du_imr = scc->imask;
840 }
841 out:
842 splx(s);
843 }
844
845 /*
846 * Stop output on a line.
847 */
848 /*ARGSUSED*/
849 int
850 mfcsstop(tp, flag)
851 struct tty *tp;
852 {
853 int s;
854
855 s = splser();
856 if (tp->t_state & TS_BUSY) {
857 if ((tp->t_state & TS_TTSTOP) == 0)
858 tp->t_state |= TS_FLUSH;
859 }
860 splx(s);
861 }
862
863 int
864 mfcsmctl(dev, bits, how)
865 dev_t dev;
866 int bits, how;
867 {
868 int unit, s;
869 u_char ub;
870 struct mfcs_softc *sc = mfcscd.cd_devs[dev & 31];
871
872 unit = dev & 1;
873
874 /*
875 * convert TIOCM* mask into CIA mask
876 * which is active low
877 */
878 if (how != DMGET) {
879 ub = 0;
880 /*
881 * need to save current state of DTR & RTS ?
882 */
883 if (bits & TIOCM_DTR)
884 ub |= 0x04 << unit;
885 if (bits & TIOCM_RTS)
886 ub |= 0x01 << unit;
887 }
888 s = splser();
889 switch (how) {
890 case DMSET:
891 sc->sc_regs->du_btst = ub;
892 sc->sc_regs->du_btrst = ub ^ (0x05 << unit);
893 break;
894
895 case DMBIC:
896 sc->sc_regs->du_btrst = ub;
897 ub = ~sc->sc_regs->du_ip;
898 break;
899
900 case DMBIS:
901 sc->sc_regs->du_btst = ub;
902 ub = ~sc->sc_regs->du_ip;
903 break;
904
905 case DMGET:
906 ub = ~sc->sc_regs->du_ip;
907 break;
908 }
909 (void)splx(s);
910
911 /* XXXX should keep DTR & RTS states in softc? */
912 bits = TIOCM_DTR | TIOCM_RTS;
913 if (ub & (1 << unit))
914 bits |= TIOCM_CTS;
915 if (ub & (4 << unit))
916 bits |= TIOCM_DSR;
917 if (ub & (0x10 << unit))
918 bits |= TIOCM_CD;
919 /* XXXX RI is not supported on all boards */
920 if (sc->sc_regs->pad26 & (1 << unit))
921 bits |= TIOCM_RI;
922
923 return(bits);
924 }
925
926 /*
927 * Level 6 interrupt processing for the MultiFaceCard 68681 DUART
928 */
929
930 int
931 mfcintr (scc)
932 struct mfc_softc *scc;
933 {
934 struct mfcs_softc *sc;
935 struct mfc_regs *regs;
936 struct tty *tp;
937 int istat, unit;
938 u_short c;
939
940 regs = scc->sc_regs;
941 istat = regs->du_isr & scc->imask;
942 if (istat == 0)
943 return (0);
944 unit = scc->sc_dev.dv_unit * 2;
945 if (istat & 0x02) { /* channel A receive interrupt */
946 sc = mfcscd.cd_devs[unit];
947 while (1) {
948 c = regs->du_sra << 8;
949 if ((c & 0x0100) == 0)
950 break;
951 c |= regs->du_rba;
952 if (sc->incnt == SERIBUF_SIZE)
953 ++sc->ovfl;
954 else {
955 *sc->wptr++ = c;
956 if (sc->wptr == sc->inbuf + SERIBUF_SIZE)
957 sc->wptr = sc->inbuf;
958 ++sc->incnt;
959 if (sc->incnt > SERIBUF_SIZE - 16)
960 regs->du_btrst = 1;
961 }
962 if (c & 0x1000)
963 regs->du_cra = 0x40;
964 }
965 }
966 if (istat & 0x20) { /* channel B receive interrupt */
967 sc = mfcscd.cd_devs[unit + 1];
968 while (1) {
969 c = regs->du_srb << 8;
970 if ((c & 0x0100) == 0)
971 break;
972 c |= regs->du_rbb;
973 if (sc->incnt == SERIBUF_SIZE)
974 ++sc->ovfl;
975 else {
976 *sc->wptr++ = c;
977 if (sc->wptr == sc->inbuf + SERIBUF_SIZE)
978 sc->wptr = sc->inbuf;
979 ++sc->incnt;
980 if (sc->incnt > SERIBUF_SIZE - 16)
981 regs->du_btrst = 2;
982 }
983 if (c & 0x1000)
984 regs->du_crb = 0x40;
985 }
986 }
987 if (istat & 0x01) { /* channel A transmit interrupt */
988 sc = mfcscd.cd_devs[unit];
989 tp = sc->sc_tty;
990 if (sc->ptr == sc->end) {
991 tp->t_state &= ~(TS_BUSY | TS_FLUSH);
992 scc->imask &= ~0x01;
993 regs->du_imr = scc->imask;
994 add_sicallback (tp->t_line ?
995 (sifunc_t)linesw[tp->t_line].l_start
996 : (sifunc_t)mfcsstart, tp, NULL);
997
998 }
999 else
1000 regs->du_tba = *sc->ptr++;
1001 }
1002 if (istat & 0x10) { /* channel B transmit interrupt */
1003 sc = mfcscd.cd_devs[unit + 1];
1004 tp = sc->sc_tty;
1005 if (sc->ptr == sc->end) {
1006 tp->t_state &= ~(TS_BUSY | TS_FLUSH);
1007 scc->imask &= ~0x10;
1008 regs->du_imr = scc->imask;
1009 add_sicallback (tp->t_line ?
1010 (sifunc_t)linesw[tp->t_line].l_start
1011 : (sifunc_t)mfcsstart, tp, NULL);
1012 }
1013 else
1014 regs->du_tbb = *sc->ptr++;
1015 }
1016 if (istat & 0x80) { /* input port change interrupt */
1017 c = regs->du_ipcr;
1018 printf ("%s: ipcr %02x", scc->sc_dev.dv_xname, c);
1019 }
1020 return(1);
1021 }
1022
1023 int
1024 mfcsxintr(unit)
1025 int unit;
1026 {
1027 int s1, s2, ovfl;
1028 struct mfcs_softc *sc = mfcscd.cd_devs[unit];
1029 struct tty *tp = sc->sc_tty;
1030
1031 /*
1032 * Make sure we're not interrupted by another
1033 * vbl, but allow level6 ints
1034 */
1035 s1 = spltty();
1036
1037 /*
1038 * pass along any acumulated information
1039 * while input is not blocked
1040 */
1041 while (sc->incnt && (tp->t_state & TS_TBLOCK) == 0) {
1042 /*
1043 * no collision with ser_fastint()
1044 */
1045 mfcseint(unit, *sc->rptr++);
1046
1047 ovfl = 0;
1048 /* lock against mfcs_fastint() */
1049 s2 = splser();
1050 --sc->incnt;
1051 if (sc->rptr == sc->inbuf + SERIBUF_SIZE)
1052 sc->rptr = sc->inbuf;
1053 if (sc->ovfl != 0) {
1054 ovfl = sc->ovfl;
1055 sc->ovfl = 0;
1056 }
1057 splx(s2);
1058 if (ovfl != 0)
1059 log(LOG_WARNING, "%s: %d buffer overflow!\n",
1060 sc->sc_dev.dv_xname, ovfl);
1061 }
1062 if (sc->incnt == 0 && (tp->t_state & TS_TBLOCK) == 0) {
1063 sc->sc_regs->du_btst = 1 << unit; /* XXXX */
1064 }
1065 splx(s1);
1066 }
1067
1068 int
1069 mfcseint(unit, stat)
1070 int unit, stat;
1071 {
1072 struct mfcs_softc *sc = mfcscd.cd_devs[unit];
1073 struct tty *tp;
1074 u_char ch;
1075 int c;
1076
1077 tp = sc->sc_tty;
1078 ch = stat & 0xff;
1079 c = ch;
1080
1081 if ((tp->t_state & TS_ISOPEN) == 0) {
1082 #ifdef KGDB
1083 /* we don't care about parity errors */
1084 if (kgdb_dev == makedev(sermajor, unit) && c == FRAME_END)
1085 kgdb_connect(0); /* trap into kgdb */
1086 #endif
1087 return;
1088 }
1089
1090 /*
1091 * Check for break and (if enabled) parity error.
1092 */
1093 if (stat & 0xc000)
1094 c |= TTY_FE;
1095 else if (stat & 0x2000)
1096 c |= TTY_PE;
1097
1098 if (stat & 0x1000)
1099 log(LOG_WARNING, "%s: fifo overflow\n",
1100 ((struct mfcs_softc *)mfcscd.cd_devs[unit])->sc_dev.dv_xname);
1101
1102 (*linesw[tp->t_line].l_rint)(c, tp);
1103 }
1104
1105 /*
1106 * This interrupt is periodically invoked in the vertical blank
1107 * interrupt. It's used to keep track of the modem control lines
1108 * and (new with the fast_int code) to move accumulated data
1109 * up into the tty layer.
1110 */
1111 void
1112 mfcsmint(unit)
1113 int unit;
1114 {
1115 struct tty *tp;
1116 struct mfcs_softc *sc = mfcscd.cd_devs[unit];
1117 u_char stat, last, istat;
1118
1119 tp = sc->sc_tty;
1120 if (!tp)
1121 return;
1122
1123 if ((tp->t_state & (TS_ISOPEN | TS_WOPEN)) == 0) {
1124 sc->rptr = sc->wptr = sc->inbuf;
1125 sc->incnt = 0;
1126 return;
1127 }
1128 /*
1129 * empty buffer
1130 */
1131 mfcsxintr(unit);
1132
1133 stat = ~sc->sc_regs->du_ip;
1134 last = sc->sc_mfc->last_ip;
1135 sc->sc_mfc->last_ip = stat;
1136
1137 /*
1138 * check whether any interesting signal changed state
1139 */
1140 istat = stat ^ last;
1141
1142 if ((istat & (0x10 << (unit & 1))) && /* CD changed */
1143 (SWFLAGS(tp->t_dev) & TIOCFLAG_SOFTCAR) == 0) {
1144 if (stat & (0x10 << (unit & 1)))
1145 (*linesw[tp->t_line].l_modem)(tp, 1);
1146 else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
1147 sc->sc_regs->du_btrst = 0x0a << (unit & 1);
1148 }
1149 }
1150 }
1151