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