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