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