mfc.c revision 1.5 1 /* $NetBSD: mfc.c,v 1.5 1995/04/23 18:24:38 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];
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 int unit, error, s;
450
451 error = 0;
452 unit = dev & 0x1f;
453
454 if (unit >= NMFCS || (mfcs_active & (1 << unit)) == 0)
455 return (ENXIO);
456
457 s = spltty();
458
459 if (mfcs_tty[unit])
460 tp = mfcs_tty[unit];
461 else
462 tp = mfcs_tty[unit] = ttymalloc();
463
464 tp->t_oproc = (void (*) (struct tty *)) mfcsstart;
465 tp->t_param = mfcsparam;
466 tp->t_dev = dev;
467 tp->t_hwiflow = mfcshwiflow;
468
469 if ((tp->t_state & TS_ISOPEN) == 0) {
470 tp->t_state |= TS_WOPEN;
471 ttychars(tp);
472 if (tp->t_ispeed == 0) {
473 /*
474 * only when cleared do we reset to defaults.
475 */
476 tp->t_iflag = TTYDEF_IFLAG;
477 tp->t_oflag = TTYDEF_OFLAG;
478 tp->t_cflag = TTYDEF_CFLAG;
479 tp->t_lflag = TTYDEF_LFLAG;
480 tp->t_ispeed = tp->t_ospeed = mfcsdefaultrate;
481 }
482 /*
483 * do these all the time
484 */
485 if (mfcsswflags[unit] & TIOCFLAG_CLOCAL)
486 tp->t_cflag |= CLOCAL;
487 if (mfcsswflags[unit] & TIOCFLAG_CRTSCTS)
488 tp->t_cflag |= CRTSCTS;
489 if (mfcsswflags[unit] & TIOCFLAG_MDMBUF)
490 tp->t_cflag |= MDMBUF;
491 mfcsparam(tp, &tp->t_termios);
492 ttsetwater(tp);
493
494 (void)mfcsmctl(dev, TIOCM_DTR | TIOCM_RTS, DMSET);
495 if ((SWFLAGS(dev) & TIOCFLAG_SOFTCAR) ||
496 (mfcsmctl(dev, 0, DMGET) & TIOCM_CD))
497 tp->t_state |= TS_CARR_ON;
498 else
499 tp->t_state &= ~TS_CARR_ON;
500 } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
501 splx(s);
502 return(EBUSY);
503 }
504
505 /*
506 * if NONBLOCK requested, ignore carrier
507 */
508 if (flag & O_NONBLOCK)
509 goto done;
510
511 /*
512 * block waiting for carrier
513 */
514 while ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0) {
515 tp->t_state |= TS_WOPEN;
516 error = ttysleep(tp, (caddr_t)&tp->t_rawq,
517 TTIPRI | PCATCH, ttopen, 0);
518 if (error) {
519 splx(s);
520 return(error);
521 }
522 }
523 done:
524 /* This is a way to handle lost XON characters */
525 if ((flag & O_TRUNC) && (tp->t_state & TS_TTSTOP)) {
526 tp->t_state &= ~TS_TTSTOP;
527 ttstart (tp);
528 }
529
530 splx(s);
531 /*
532 * Reset the tty pointer, as there could have been a dialout
533 * use of the tty with a dialin open waiting.
534 */
535 tp->t_dev = dev;
536 return((*linesw[tp->t_line].l_open)(dev, tp));
537 }
538
539 /*ARGSUSED*/
540 int
541 mfcsclose(dev, flag, mode, p)
542 dev_t dev;
543 int flag, mode;
544 struct proc *p;
545 {
546 struct tty *tp;
547 int unit;
548 struct mfcs_softc *sc = mfcscd.cd_devs[dev & 31];
549 struct mfc_softc *scc= sc->sc_mfc;
550
551 unit = dev & 31;
552
553 tp = mfcs_tty[unit];
554 (*linesw[tp->t_line].l_close)(tp, flag);
555 sc->sc_duart->ch_cr = 0x70; /* stop break */
556
557 scc->imask &= ~(0x7 << ((unit & 1) * 4));
558 scc->sc_regs->du_imr = scc->imask;
559 if (sc->flags & CT_USED) {
560 --scc->ct_usecnt;
561 sc->flags &= ~CT_USED;
562 }
563
564 /*
565 * If the device is closed, it's close, no matter whether we deal with
566 * modem control signals nor not.
567 */
568 #if 0
569 if (tp->t_cflag & HUPCL || tp->t_state & TS_WOPEN ||
570 (tp->t_state & TS_ISOPEN) == 0)
571 #endif
572 (void) mfcsmctl(dev, 0, DMSET);
573 ttyclose(tp);
574 #if not_yet
575 if (tp != &mfcs_cons) {
576 remove_vbl_function(&mfcs_vbl_node[unit]);
577 ttyfree(tp);
578 mfcs_tty[unit] = (struct tty *) NULL;
579 }
580 #endif
581 return (0);
582 }
583
584 int
585 mfcsread(dev, uio, flag)
586 dev_t dev;
587 struct uio *uio;
588 int flag;
589 {
590 struct tty *tp;
591 if ((tp = mfcs_tty[dev & 31]) == NULL)
592 return(ENXIO);
593 return((*linesw[tp->t_line].l_read)(tp, uio, flag));
594 }
595
596 int
597 mfcswrite(dev, uio, flag)
598 dev_t dev;
599 struct uio *uio;
600 int flag;
601 {
602 struct tty *tp;
603
604 if ((tp = mfcs_tty[dev & 31]) == NULL)
605 return(ENXIO);
606 return((*linesw[tp->t_line].l_write)(tp, uio, flag));
607 }
608
609 struct tty *
610 mfcstty(dev)
611 dev_t dev;
612 {
613 return (mfcs_tty[dev & 31]);
614 }
615
616 int
617 mfcsioctl(dev, cmd, data, flag, p)
618 dev_t dev;
619 caddr_t data;
620 struct proc *p;
621 {
622 register struct tty *tp;
623 register int unit = dev & 31;
624 register int error;
625 struct mfcs_softc *sc = mfcscd.cd_devs[dev & 31];
626
627 tp = mfcs_tty[unit];
628 if (!tp)
629 return ENXIO;
630
631 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
632 if (error >= 0)
633 return(error);
634
635 error = ttioctl(tp, cmd, data, flag, p);
636 if (error >= 0)
637 return(error);
638
639 switch (cmd) {
640 case TIOCSBRK:
641 sc->sc_duart->ch_cr = 0x60; /* start break */
642 break;
643
644 case TIOCCBRK:
645 sc->sc_duart->ch_cr = 0x70; /* stop break */
646 break;
647
648 case TIOCSDTR:
649 (void) mfcsmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
650 break;
651
652 case TIOCCDTR:
653 (void) mfcsmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
654 break;
655
656 case TIOCMSET:
657 (void) mfcsmctl(dev, *(int *) data, DMSET);
658 break;
659
660 case TIOCMBIS:
661 (void) mfcsmctl(dev, *(int *) data, DMBIS);
662 break;
663
664 case TIOCMBIC:
665 (void) mfcsmctl(dev, *(int *) data, DMBIC);
666 break;
667
668 case TIOCMGET:
669 *(int *)data = mfcsmctl(dev, 0, DMGET);
670 break;
671 case TIOCGFLAGS:
672 *(int *)data = SWFLAGS(dev);
673 break;
674 case TIOCSFLAGS:
675 error = suser(p->p_ucred, &p->p_acflag);
676 if (error != 0)
677 return(EPERM);
678
679 mfcsswflags[unit] = *(int *)data;
680 mfcsswflags[unit] &= /* only allow valid flags */
681 (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
682 /* XXXX need to change duart parameters? */
683 break;
684 default:
685 return(ENOTTY);
686 }
687
688 return(0);
689 }
690
691 int
692 mfcsparam(tp, t)
693 struct tty *tp;
694 struct termios *t;
695 {
696 int cfcr, cflag, unit, ospeed;
697 struct mfcs_softc *sc = mfcscd.cd_devs[tp->t_dev & 31];
698 struct mfc_softc *scc= sc->sc_mfc;
699
700 cflag = t->c_cflag;
701 unit = tp->t_dev & 31;
702 if (sc->flags & CT_USED) {
703 --scc->ct_usecnt;
704 sc->flags &= ~CT_USED;
705 }
706 ospeed = ttspeedtab(t->c_ospeed, scc->mfc_iii ? mfcs3speedtab2 :
707 mfcs2speedtab2);
708
709 /*
710 * If Baud Rate Generator can't generate requested speed,
711 * try to use the counter/timer.
712 */
713 if (ospeed < 0 && (scc->clk_frq % t->c_ospeed) == 0) {
714 ospeed = scc->clk_frq / t->c_ospeed; /* divisor */
715 if (scc->ct_usecnt > 0 && scc->ct_val != ospeed)
716 ospeed = -1;
717 else {
718 scc->sc_regs->du_ctur = ospeed >> 8;
719 scc->sc_regs->du_ctlr = ospeed;
720 scc->ct_val = ospeed;
721 ++scc->ct_usecnt;
722 sc->flags |= CT_USED;
723 ospeed = 0xdd;
724 }
725 }
726 /* XXXX 68681 duart could handle split speeds */
727 if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
728 return(EINVAL);
729
730 /* XXXX handle parity, character size, stop bits, flow control */
731
732 /*
733 * copy to tty
734 */
735 tp->t_ispeed = t->c_ispeed;
736 tp->t_ospeed = t->c_ospeed;
737 tp->t_cflag = cflag;
738
739 /*
740 * enable interrupts
741 */
742 scc->imask |= (0x2 << ((unit & 1) * 4)) | 0x80;
743 scc->sc_regs->du_imr = scc->imask;
744 #if defined(DEBUG) && 0
745 printf("mfcsparam: speed %d => %x ct %d imask %x cflag %x\n",
746 t->c_ospeed, ospeed, scc->ct_val, scc->imask, cflag);
747 #endif
748 if (ospeed == 0)
749 (void)mfcsmctl(tp->t_dev, 0, DMSET); /* hang up line */
750 else {
751 /*
752 * (re)enable DTR
753 * and set baud rate. (8 bit mode)
754 */
755 (void)mfcsmctl(tp->t_dev, TIOCM_DTR | TIOCM_RTS, DMSET);
756 sc->sc_duart->ch_csr = ospeed;
757 }
758 return(0);
759 }
760
761 int mfcshwiflow(tp, flag)
762 struct tty *tp;
763 int flag;
764 {
765 struct mfcs_softc *sc = mfcscd.cd_devs[tp->t_dev & 31];
766 int unit = tp->t_dev & 1;
767
768 if (flag)
769 sc->sc_regs->du_btrst = 1 << unit;
770 else
771 sc->sc_regs->du_btst = 1 << unit;
772 return 1;
773 }
774
775 int
776 mfcsstart(tp)
777 struct tty *tp;
778 {
779 int cc, s, unit;
780 struct mfcs_softc *sc = mfcscd.cd_devs[tp->t_dev & 31];
781 struct mfc_softc *scc= sc->sc_mfc;
782
783 if ((tp->t_state & TS_ISOPEN) == 0)
784 return;
785
786 unit = tp->t_dev & 1;
787
788 s = splser();
789 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
790 goto out;
791
792 cc = tp->t_outq.c_cc;
793 if (cc <= tp->t_lowat) {
794 if (tp->t_state & TS_ASLEEP) {
795 tp->t_state &= ~TS_ASLEEP;
796 wakeup((caddr_t) & tp->t_outq);
797 }
798 selwakeup(&tp->t_wsel);
799 }
800 if (cc == 0 || (tp->t_state & TS_BUSY))
801 goto out;
802
803 /*
804 * We only do bulk transfers if using CTSRTS flow control, not for
805 * (probably sloooow) ixon/ixoff devices.
806 */
807 if ((tp->t_cflag & CRTSCTS) == 0)
808 cc = 1;
809
810 /*
811 * Limit the amount of output we do in one burst
812 * to prevent hogging the CPU.
813 */
814 if (cc > SEROBUF_SIZE)
815 cc = SEROBUF_SIZE;
816 cc = q_to_b(&tp->t_outq, sc->outbuf, cc);
817 if (cc > 0) {
818 tp->t_state |= TS_BUSY;
819
820 sc->ptr = sc->outbuf;
821 sc->end = sc->outbuf + cc;
822
823 /*
824 * Get first character out, then have TBE-interrupts blow out
825 * further characters, until buffer is empty, and TS_BUSY gets
826 * cleared.
827 */
828 sc->sc_duart->ch_tb = *sc->ptr++;
829 scc->imask |= 1 << (unit * 4);
830 sc->sc_regs->du_imr = scc->imask;
831 }
832 out:
833 splx(s);
834 }
835
836 /*
837 * Stop output on a line.
838 */
839 /*ARGSUSED*/
840 int
841 mfcsstop(tp, flag)
842 struct tty *tp;
843 {
844 int s;
845
846 s = splser();
847 if (tp->t_state & TS_BUSY) {
848 if ((tp->t_state & TS_TTSTOP) == 0)
849 tp->t_state |= TS_FLUSH;
850 }
851 splx(s);
852 }
853
854 int
855 mfcsmctl(dev, bits, how)
856 dev_t dev;
857 int bits, how;
858 {
859 int unit, s;
860 u_char ub;
861 struct mfcs_softc *sc = mfcscd.cd_devs[dev & 31];
862
863 unit = dev & 1;
864
865 /*
866 * convert TIOCM* mask into CIA mask
867 * which is active low
868 */
869 if (how != DMGET) {
870 ub = 0;
871 /*
872 * need to save current state of DTR & RTS ?
873 */
874 if (bits & TIOCM_DTR)
875 ub |= 0x04 << unit;
876 if (bits & TIOCM_RTS)
877 ub |= 0x01 << unit;
878 }
879 s = splser();
880 switch (how) {
881 case DMSET:
882 sc->sc_regs->du_btst = ub;
883 sc->sc_regs->du_btrst = ub ^ (0x05 << unit);
884 break;
885
886 case DMBIC:
887 sc->sc_regs->du_btrst = ub;
888 ub = ~sc->sc_regs->du_ip;
889 break;
890
891 case DMBIS:
892 sc->sc_regs->du_btst = ub;
893 ub = ~sc->sc_regs->du_ip;
894 break;
895
896 case DMGET:
897 ub = ~sc->sc_regs->du_ip;
898 break;
899 }
900 (void)splx(s);
901
902 /* XXXX should keep DTR & RTS states in softc? */
903 bits = TIOCM_DTR | TIOCM_RTS;
904 if (ub & (1 << unit))
905 bits |= TIOCM_CTS;
906 if (ub & (4 << unit))
907 bits |= TIOCM_DSR;
908 if (ub & (0x10 << unit))
909 bits |= TIOCM_CD;
910 /* XXXX RI is not supported on all boards */
911 if (sc->sc_regs->pad26 & (1 << unit))
912 bits |= TIOCM_RI;
913
914 return(bits);
915 }
916
917 /*
918 * Level 6 interrupt processing for the MultiFaceCard 68681 DUART
919 */
920
921 int
922 mfcintr (scc)
923 struct mfc_softc *scc;
924 {
925 struct mfcs_softc *sc;
926 struct mfc_regs *regs;
927 struct tty *tp;
928 int istat, unit;
929 u_short c;
930
931 regs = scc->sc_regs;
932 istat = regs->du_isr & scc->imask;
933 if (istat == 0)
934 return (0);
935 unit = scc->sc_dev.dv_unit * 2;
936 if (istat & 0x02) { /* channel A receive interrupt */
937 sc = mfcscd.cd_devs[unit];
938 while (1) {
939 c = regs->du_sra << 8;
940 if ((c & 0x0100) == 0)
941 break;
942 c |= regs->du_rba;
943 if (sc->incnt == SERIBUF_SIZE)
944 ++sc->ovfl;
945 else {
946 *sc->wptr++ = c;
947 if (sc->wptr == sc->inbuf + SERIBUF_SIZE)
948 sc->wptr = sc->inbuf;
949 ++sc->incnt;
950 if (sc->incnt > SERIBUF_SIZE - 16)
951 regs->du_btrst = 1;
952 }
953 if (c & 0x1000)
954 regs->du_cra = 0x40;
955 }
956 }
957 if (istat & 0x20) { /* channel B receive interrupt */
958 sc = mfcscd.cd_devs[unit + 1];
959 while (1) {
960 c = regs->du_srb << 8;
961 if ((c & 0x0100) == 0)
962 break;
963 c |= regs->du_rbb;
964 if (sc->incnt == SERIBUF_SIZE)
965 ++sc->ovfl;
966 else {
967 *sc->wptr++ = c;
968 if (sc->wptr == sc->inbuf + SERIBUF_SIZE)
969 sc->wptr = sc->inbuf;
970 ++sc->incnt;
971 if (sc->incnt > SERIBUF_SIZE - 16)
972 regs->du_btrst = 2;
973 }
974 if (c & 0x1000)
975 regs->du_crb = 0x40;
976 }
977 }
978 if (istat & 0x01) { /* channel A transmit interrupt */
979 tp = mfcs_tty[unit];
980 sc = mfcscd.cd_devs[unit];
981 if (sc->ptr == sc->end) {
982 tp->t_state &= ~(TS_BUSY | TS_FLUSH);
983 scc->imask &= ~0x01;
984 regs->du_imr = scc->imask;
985 add_sicallback (tp->t_line ?
986 linesw[tp->t_line].l_start : mfcsstart,
987 tp, NULL);
988
989 }
990 else
991 regs->du_tba = *sc->ptr++;
992 }
993 if (istat & 0x10) { /* channel B transmit interrupt */
994 tp = mfcs_tty[unit + 1];
995 sc = mfcscd.cd_devs[unit + 1];
996 if (sc->ptr == sc->end) {
997 tp->t_state &= ~(TS_BUSY | TS_FLUSH);
998 scc->imask &= ~0x10;
999 regs->du_imr = scc->imask;
1000 add_sicallback (tp->t_line ?
1001 linesw[tp->t_line].l_start : mfcsstart,
1002 tp, NULL);
1003 }
1004 else
1005 regs->du_tbb = *sc->ptr++;
1006 }
1007 if (istat & 0x80) { /* input port change interrupt */
1008 c = regs->du_ipcr;
1009 printf ("%s: ipcr %02x", scc->sc_dev.dv_xname, c);
1010 }
1011 return(1);
1012 }
1013
1014 int
1015 mfcsxintr(unit)
1016 int unit;
1017 {
1018 int s1, s2, ovfl;
1019 struct mfcs_softc *sc = mfcscd.cd_devs[unit];
1020 struct tty *tp = mfcs_tty[unit];
1021
1022 /*
1023 * Make sure we're not interrupted by another
1024 * vbl, but allow level6 ints
1025 */
1026 s1 = spltty();
1027
1028 /*
1029 * pass along any acumulated information
1030 * while input is not blocked
1031 */
1032 while (sc->incnt && (tp->t_state & TS_TBLOCK) == 0) {
1033 /*
1034 * no collision with ser_fastint()
1035 */
1036 mfcseint(unit, *sc->rptr++);
1037
1038 ovfl = 0;
1039 /* lock against mfcs_fastint() */
1040 s2 = splser();
1041 --sc->incnt;
1042 if (sc->rptr == sc->inbuf + SERIBUF_SIZE)
1043 sc->rptr = sc->inbuf;
1044 if (sc->ovfl != 0) {
1045 ovfl = sc->ovfl;
1046 sc->ovfl = 0;
1047 }
1048 splx(s2);
1049 if (ovfl != 0)
1050 log(LOG_WARNING, "%s: %d buffer overflow!\n",
1051 sc->sc_dev.dv_xname, ovfl);
1052 }
1053 if (sc->incnt == 0 && (tp->t_state & TS_TBLOCK) == 0) {
1054 sc->sc_regs->du_btst = 1 << unit; /* XXXX */
1055 }
1056 splx(s1);
1057 }
1058
1059 int
1060 mfcseint(unit, stat)
1061 int unit, stat;
1062 {
1063 struct tty *tp;
1064 u_char ch;
1065 int c;
1066
1067 tp = mfcs_tty[unit];
1068 ch = stat & 0xff;
1069 c = ch;
1070
1071 if ((tp->t_state & TS_ISOPEN) == 0) {
1072 #ifdef KGDB
1073 /* we don't care about parity errors */
1074 if (kgdb_dev == makedev(sermajor, unit) && c == FRAME_END)
1075 kgdb_connect(0); /* trap into kgdb */
1076 #endif
1077 return;
1078 }
1079
1080 /*
1081 * Check for break and (if enabled) parity error.
1082 */
1083 if (stat & 0xc000)
1084 c |= TTY_FE;
1085 else if (stat & 0x2000)
1086 c |= TTY_PE;
1087
1088 if (stat & 0x1000)
1089 log(LOG_WARNING, "%s: fifo overflow\n",
1090 ((struct mfcs_softc *)mfcscd.cd_devs[unit])->sc_dev.dv_xname);
1091
1092 (*linesw[tp->t_line].l_rint)(c, tp);
1093 }
1094
1095 /*
1096 * This interrupt is periodically invoked in the vertical blank
1097 * interrupt. It's used to keep track of the modem control lines
1098 * and (new with the fast_int code) to move accumulated data
1099 * up into the tty layer.
1100 */
1101 void
1102 mfcsmint(unit)
1103 int unit;
1104 {
1105 struct tty *tp;
1106 struct mfcs_softc *sc = mfcscd.cd_devs[unit];
1107 u_char stat, last, istat;
1108
1109 tp = mfcs_tty[unit];
1110 if (!tp)
1111 return;
1112
1113 if ((tp->t_state & (TS_ISOPEN | TS_WOPEN)) == 0) {
1114 sc->rptr = sc->wptr = sc->inbuf;
1115 sc->incnt = 0;
1116 return;
1117 }
1118 /*
1119 * empty buffer
1120 */
1121 mfcsxintr(unit);
1122
1123 stat = ~sc->sc_regs->du_ip;
1124 last = sc->sc_mfc->last_ip;
1125 sc->sc_mfc->last_ip = stat;
1126
1127 /*
1128 * check whether any interesting signal changed state
1129 */
1130 istat = stat ^ last;
1131
1132 if ((istat & (0x10 << (unit & 1))) && /* CD changed */
1133 (SWFLAGS(tp->t_dev) & TIOCFLAG_SOFTCAR) == 0) {
1134 if (stat & (0x10 << (unit & 1)))
1135 (*linesw[tp->t_line].l_modem)(tp, 1);
1136 else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
1137 sc->sc_regs->du_btrst = 0x0a << (unit & 1);
1138 }
1139 }
1140 }
1141