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