1 /* $NetBSD: mfc.c,v 1.52 2009/05/19 18:39:26 phx Exp $ */
4 * Copyright (c) 1982, 1990 The Regents of the University of California.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * Copyright (c) 1994 Michael L. Hitch
34 * Redistribution and use in source and binary forms, with or without
35 * modification, are permitted provided that the following conditions
37 * 1. Redistributions of source code must retain the above copyright
38 * notice, this list of conditions and the following disclaimer.
39 * 2. Redistributions in binary form must reproduce the above copyright
40 * notice, this list of conditions and the following disclaimer in the
41 * documentation and/or other materials provided with the distribution.
43 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
44 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
45 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
46 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
47 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
48 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
49 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
50 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
51 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
52 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
57 #include <sys/cdefs.h>
58 __KERNEL_RCSID(0, "$NetBSD: mfc.c,v 1.52 2009/05/19 18:39:26 phx Exp $");
60 #include <sys/param.h>
61 #include <sys/systm.h>
62 #include <sys/kernel.h>
63 #include <sys/device.h>
67 #include <sys/malloc.h>
69 #include <sys/syslog.h>
70 #include <sys/queue.h>
72 #include <sys/kauth.h>
73 #include <machine/cpu.h>
74 #include <amiga/amiga/device.h>
75 #include <amiga/amiga/isr.h>
76 #include <amiga/amiga/custom.h>
77 #include <amiga/amiga/cia.h>
78 #include <amiga/amiga/cc.h>
79 #include <amiga/dev/zbusvar.h>
86 #define SEROBUF_SIZE 128
89 #define SERIBUF_SIZE 1024
92 #define splser() spl6()
95 * 68581 DUART registers
98 volatile u_char du_mr1a
;
99 #define du_mr2a du_mr1a
101 volatile u_char du_csra
;
102 #define du_sra du_csra
104 volatile u_char du_cra
;
106 volatile u_char du_tba
;
107 #define du_rba du_tba
109 volatile u_char du_acr
;
110 #define du_ipcr du_acr
112 volatile u_char du_imr
;
113 #define du_isr du_imr
115 volatile u_char du_ctur
;
116 #define du_cmsb du_ctur
118 volatile u_char du_ctlr
;
119 #define du_clsb du_ctlr
121 volatile u_char du_mr1b
;
122 #define du_mr2b du_mr1b
124 volatile u_char du_csrb
;
125 #define du_srb du_csrb
127 volatile u_char du_crb
;
129 volatile u_char du_tbb
;
130 #define du_rbb du_tbb
132 volatile u_char du_ivr
;
134 volatile u_char du_opcr
;
135 #define du_ip du_opcr
137 volatile u_char du_btst
;
138 #define du_strc du_btst
140 volatile u_char du_btrst
;
141 #define du_stpc du_btrst
146 * 68681 DUART serial port registers
149 volatile u_char ch_mr1
;
150 #define ch_mr2 ch_mr1
152 volatile u_char ch_csr
;
155 volatile u_char ch_cr
;
157 volatile u_char ch_tb
;
163 struct device sc_dev
;
165 struct mfc_regs
*sc_regs
;
176 struct device sc_dev
;
178 struct duart_regs
*sc_duart
;
179 struct mfc_regs
*sc_regs
;
180 struct mfc_softc
*sc_mfc
;
182 long flags
; /* XXX */
183 #define CT_USED 1 /* CT in use */
184 u_short
*rptr
, *wptr
, incnt
, ovfl
;
185 u_short inbuf
[SERIBUF_SIZE
];
187 char outbuf
[SEROBUF_SIZE
];
188 struct vbl_node vbl_node
;
199 struct zbus_args zargs
;
204 int mfcprint(void *auxp
, const char *);
205 void mfcattach(struct device
*, struct device
*, void *);
206 int mfcmatch(struct device
*, struct cfdata
*, void *);
209 int mfcsmatch(struct device
*, struct cfdata
*, void *);
210 void mfcsattach(struct device
*, struct device
*, void *);
211 int mfcsparam( struct tty
*, struct termios
*);
212 int mfcshwiflow(struct tty
*, int);
213 void mfcsstart(struct tty
*);
214 int mfcsmctl(dev_t
, int, int);
216 void mfcseint(int, int);
217 void mfcsmint(register int);
218 void mfcs_intr_soft(void *);
222 void mfcpattach(struct device
*, struct device
*, void *);
223 int mfcpmatch(struct device
*, struct cfdata
*, void *);
227 CFATTACH_DECL(mfc
, sizeof(struct mfc_softc
),
228 mfcmatch
, mfcattach
, NULL
, NULL
);
231 CFATTACH_DECL(mfcs
, sizeof(struct mfcs_softc
),
232 mfcsmatch
, mfcsattach
, NULL
, NULL
);
234 extern struct cfdriver mfcs_cd
;
238 CFATTACH_DECL(mfcp
, sizeof(struct mfcp_softc
),
239 mfcpmatch
, mfcpattach
, NULL
, NULL
);
242 dev_type_open(mfcsopen
);
243 dev_type_close(mfcsclose
);
244 dev_type_read(mfcsread
);
245 dev_type_write(mfcswrite
);
246 dev_type_ioctl(mfcsioctl
);
247 dev_type_stop(mfcsstop
);
248 dev_type_tty(mfcstty
);
249 dev_type_poll(mfcspoll
);
251 const struct cdevsw mfcs_cdevsw
= {
252 mfcsopen
, mfcsclose
, mfcsread
, mfcswrite
, mfcsioctl
,
253 mfcsstop
, mfcstty
, mfcspoll
, nommap
, ttykqfilter
, D_TTY
257 int mfcsdefaultrate
= 38400 /*TTYDEF_SPEED*/;
258 #define SWFLAGS(dev) (sc->swflags | (((dev) & 0x80) == 0 ? TIOCFLAG_SOFTCAR : 0))
262 * MultiFaceCard III, II+ (not supported yet), and
263 * SerialMaster 500+ (not supported yet)
264 * baud rate tables for BRG set 1 [not used yet]
267 const struct speedtab mfcs3speedtab1
[] = {
282 * MultiFaceCard II, I, and SerialMaster 500
283 * baud rate tables for BRG set 1 [not used yet]
286 const struct speedtab mfcs2speedtab1
[] = {
302 * MultiFaceCard III, II+ (not supported yet), and
303 * SerialMaster 500+ (not supported yet)
304 * baud rate tables for BRG set 2
307 const struct speedtab mfcs3speedtab2
[] = {
323 * MultiFaceCard II, I, and SerialMaster 500
324 * baud rate tables for BRG set 2
327 const struct speedtab mfcs2speedtab2
[] = {
343 * if we are an bsc/Alf Data MultFaceCard (I, II, and III)
346 mfcmatch(struct device
*pdp
, struct cfdata
*cfp
, void *auxp
)
348 struct zbus_args
*zap
;
351 if (zap
->manid
== 2092 &&
352 (zap
->prodid
== 16 || zap
->prodid
== 17 || zap
->prodid
== 18))
359 mfcattach(struct device
*pdp
, struct device
*dp
, void *auxp
)
361 struct mfc_softc
*scc
;
362 struct zbus_args
*zap
;
371 scc
= (struct mfc_softc
*)dp
;
372 unit
= device_unit(&scc
->sc_dev
);
373 scc
->sc_regs
= rp
= zap
->va
;
374 if (zap
->prodid
== 18)
376 scc
->clk_frq
= scc
->mfc_iii
? 230400 : 115200;
378 rp
->du_opcr
= 0x00; /* configure output port? */
379 rp
->du_btrst
= 0x0f; /* clear modem lines */
380 rp
->du_ivr
= 0; /* IVR */
381 rp
->du_imr
= 0; /* IMR */
382 rp
->du_acr
= 0xe0; /* baud rate generate set 2 */
385 rp
->du_csra
= 0xcc; /* clock select = 38400 */
386 rp
->du_cra
= 0x10; /* reset mode register ptr */
390 rp
->du_mr1a
= 0x93; /* MRA1 */
391 rp
->du_mr2a
= 0x17; /* MRA2 */
392 rp
->du_csrb
= 0xcc; /* clock select = 38400 */
393 rp
->du_crb
= 0x10; /* reset mode register ptr */
397 rp
->du_mr1b
= 0x93; /* MRB1 */
398 rp
->du_mr2b
= 0x17; /* MRB2 */
399 rp
->du_cra
= 0x05; /* enable A Rx & Tx */
400 rp
->du_crb
= 0x05; /* enable B Rx & Tx */
402 scc
->sc_isr
.isr_intr
= mfcintr
;
403 scc
->sc_isr
.isr_arg
= scc
;
404 scc
->sc_isr
.isr_ipl
= 6;
405 add_isr(&scc
->sc_isr
);
407 /* configure ports */
408 memcpy(&ma
.zargs
, zap
, sizeof(struct zbus_args
));
411 config_found(dp
, &ma
, mfcprint
);
412 ma
.unit
= unit
* 2 + 1;
413 config_found(dp
, &ma
, mfcprint
);
416 config_found(dp
, &ma
, mfcprint
);
423 mfcsmatch(struct device
*pdp
, struct cfdata
*cfp
, void *auxp
)
428 if (strcmp(ma
->subdev
, "mfcs") == 0)
434 mfcsattach(struct device
*pdp
, struct device
*dp
, void *auxp
)
437 struct mfcs_softc
*sc
;
438 struct mfc_softc
*scc
;
442 sc
= device_private(dp
);
443 scc
= device_private(pdp
);
446 printf (": input fifo %d output fifo %d\n", SERIBUF_SIZE
,
450 mfcs_active
|= 1 << unit
;
451 sc
->rptr
= sc
->wptr
= sc
->inbuf
;
453 sc
->sc_regs
= rp
= scc
->sc_regs
;
454 sc
->sc_duart
= (struct duart_regs
*) ((unit
& 1) ?
455 __UNVOLATILE(&rp
->du_mr1b
) : __UNVOLATILE(&rp
->du_mr1a
));
456 sc
->mfcs_si
= softint_establish(SOFTINT_SERIAL
, mfcs_intr_soft
, sc
);
458 * should have only one vbl routine to handle all ports?
460 sc
->vbl_node
.function
= (void (*) (void *)) mfcsmint
;
461 sc
->vbl_node
.data
= (void *) unit
;
462 add_vbl_function(&sc
->vbl_node
, 1, (void *) unit
);
466 * print diag if pnp is NULL else just extra
469 mfcprint(void *auxp
, const char *pnp
)
477 mfcsopen(dev_t dev
, int flag
, int mode
, struct lwp
*l
)
480 struct mfcs_softc
*sc
;
486 sc
= device_lookup_private(&mfcs_cd
, unit
);
487 if (sc
== NULL
|| (mfcs_active
& (1 << unit
)) == 0)
493 tp
= sc
->sc_tty
= ttymalloc();
497 tp
->t_oproc
= (void (*) (struct tty
*)) mfcsstart
;
498 tp
->t_param
= mfcsparam
;
500 tp
->t_hwiflow
= mfcshwiflow
;
502 if (kauth_authorize_device_tty(l
->l_cred
, KAUTH_DEVICE_TTY_OPEN
, tp
))
505 mutex_spin_enter(&tty_lock
);
506 if ((tp
->t_state
& TS_ISOPEN
) == 0 && tp
->t_wopen
== 0) {
508 if (tp
->t_ispeed
== 0) {
510 * only when cleared do we reset to defaults.
512 tp
->t_iflag
= TTYDEF_IFLAG
;
513 tp
->t_oflag
= TTYDEF_OFLAG
;
514 tp
->t_cflag
= TTYDEF_CFLAG
;
515 tp
->t_lflag
= TTYDEF_LFLAG
;
516 tp
->t_ispeed
= tp
->t_ospeed
= mfcsdefaultrate
;
519 * do these all the time
521 if (sc
->swflags
& TIOCFLAG_CLOCAL
)
522 tp
->t_cflag
|= CLOCAL
;
523 if (sc
->swflags
& TIOCFLAG_CRTSCTS
)
524 tp
->t_cflag
|= CRTSCTS
;
525 if (sc
->swflags
& TIOCFLAG_MDMBUF
)
526 tp
->t_cflag
|= MDMBUF
;
527 mfcsparam(tp
, &tp
->t_termios
);
530 (void)mfcsmctl(dev
, TIOCM_DTR
| TIOCM_RTS
, DMSET
);
531 if ((SWFLAGS(dev
) & TIOCFLAG_SOFTCAR
) ||
532 (mfcsmctl(dev
, 0, DMGET
) & TIOCM_CD
))
533 tp
->t_state
|= TS_CARR_ON
;
535 tp
->t_state
&= ~TS_CARR_ON
;
539 * if NONBLOCK requested, ignore carrier
541 if (flag
& O_NONBLOCK
)
545 * block waiting for carrier
547 while ((tp
->t_state
& TS_CARR_ON
) == 0 && (tp
->t_cflag
& CLOCAL
) == 0) {
549 error
= ttysleep(tp
, &tp
->t_rawcv
, true, 0);
552 mutex_spin_exit(&tty_lock
);
557 /* This is a way to handle lost XON characters */
558 if ((flag
& O_TRUNC
) && (tp
->t_state
& TS_TTSTOP
)) {
559 tp
->t_state
&= ~TS_TTSTOP
;
563 * Reset the tty pointer, as there could have been a dialout
564 * use of the tty with a dialin open waiting.
567 mutex_spin_exit(&tty_lock
);
568 return tp
->t_linesw
->l_open(dev
, tp
);
573 mfcsclose(dev_t dev
, int flag
, int mode
, struct lwp
*l
)
577 struct mfcs_softc
*sc
= device_lookup_private(&mfcs_cd
, dev
& 31);
578 struct mfc_softc
*scc
= sc
->sc_mfc
;
583 tp
->t_linesw
->l_close(tp
, flag
);
584 sc
->sc_duart
->ch_cr
= 0x70; /* stop break */
586 scc
->imask
&= ~(0x7 << ((unit
& 1) * 4));
587 scc
->sc_regs
->du_imr
= scc
->imask
;
588 if (sc
->flags
& CT_USED
) {
590 sc
->flags
&= ~CT_USED
;
594 * If the device is closed, it's close, no matter whether we deal with
595 * modem control signals nor not.
598 if (tp
->t_cflag
& HUPCL
|| tp
->t_wopen
!= 0 ||
599 (tp
->t_state
& TS_ISOPEN
) == 0)
601 (void) mfcsmctl(dev
, 0, DMSET
);
604 if (tp
!= &mfcs_cons
) {
605 remove_vbl_function(&sc
->vbl_node
);
607 sc
->sc_tty
= (struct tty
*) NULL
;
614 mfcsread(dev_t dev
, struct uio
*uio
, int flag
)
616 struct mfcs_softc
*sc
= device_lookup_private(&mfcs_cd
, dev
& 31);
617 struct tty
*tp
= sc
->sc_tty
;
620 return tp
->t_linesw
->l_read(tp
, uio
, flag
);
624 mfcswrite(dev_t dev
, struct uio
*uio
, int flag
)
626 struct mfcs_softc
*sc
= device_lookup_private(&mfcs_cd
, dev
& 31);
627 struct tty
*tp
= sc
->sc_tty
;
631 return tp
->t_linesw
->l_write(tp
, uio
, flag
);
635 mfcspoll(dev_t dev
, int events
, struct lwp
*l
)
637 struct mfcs_softc
*sc
= device_lookup_private(&mfcs_cd
, dev
& 31);
638 struct tty
*tp
= sc
->sc_tty
;
642 return ((*tp
->t_linesw
->l_poll
)(tp
, events
, l
));
648 struct mfcs_softc
*sc
= device_lookup_private(&mfcs_cd
, dev
& 31);
654 mfcsioctl(dev_t dev
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
656 register struct tty
*tp
;
658 struct mfcs_softc
*sc
= device_lookup_private(&mfcs_cd
, dev
& 31);
664 error
= tp
->t_linesw
->l_ioctl(tp
, cmd
, data
, flag
, l
);
665 if (error
!= EPASSTHROUGH
)
668 error
= ttioctl(tp
, cmd
, data
, flag
, l
);
669 if (error
!= EPASSTHROUGH
)
674 sc
->sc_duart
->ch_cr
= 0x60; /* start break */
678 sc
->sc_duart
->ch_cr
= 0x70; /* stop break */
682 (void) mfcsmctl(dev
, TIOCM_DTR
| TIOCM_RTS
, DMBIS
);
686 (void) mfcsmctl(dev
, TIOCM_DTR
| TIOCM_RTS
, DMBIC
);
690 (void) mfcsmctl(dev
, *(int *) data
, DMSET
);
694 (void) mfcsmctl(dev
, *(int *) data
, DMBIS
);
698 (void) mfcsmctl(dev
, *(int *) data
, DMBIC
);
702 *(int *)data
= mfcsmctl(dev
, 0, DMGET
);
705 *(int *)data
= SWFLAGS(dev
);
708 error
= kauth_authorize_device_tty(l
->l_cred
,
709 KAUTH_DEVICE_TTY_PRIVSET
, tp
);
713 sc
->swflags
= *(int *)data
;
714 sc
->swflags
&= /* only allow valid flags */
715 (TIOCFLAG_SOFTCAR
| TIOCFLAG_CLOCAL
| TIOCFLAG_CRTSCTS
);
716 /* XXXX need to change duart parameters? */
719 return(EPASSTHROUGH
);
726 mfcsparam(struct tty
*tp
, struct termios
*t
)
728 int cflag
, unit
, ospeed
;
729 struct mfcs_softc
*sc
= device_lookup_private(&mfcs_cd
, tp
->t_dev
& 31);
730 struct mfc_softc
*scc
= sc
->sc_mfc
;
733 unit
= tp
->t_dev
& 31;
734 if (sc
->flags
& CT_USED
) {
736 sc
->flags
&= ~CT_USED
;
738 ospeed
= ttspeedtab(t
->c_ospeed
, scc
->mfc_iii
? mfcs3speedtab2
:
742 * If Baud Rate Generator can't generate requested speed,
743 * try to use the counter/timer.
745 if (ospeed
< 0 && (scc
->clk_frq
% t
->c_ospeed
) == 0) {
746 ospeed
= scc
->clk_frq
/ t
->c_ospeed
; /* divisor */
747 if (scc
->ct_usecnt
> 0 && scc
->ct_val
!= ospeed
)
750 scc
->sc_regs
->du_ctur
= ospeed
>> 8;
751 scc
->sc_regs
->du_ctlr
= ospeed
;
752 scc
->ct_val
= ospeed
;
754 sc
->flags
|= CT_USED
;
758 /* XXXX 68681 duart could handle split speeds */
759 if (ospeed
< 0 || (t
->c_ispeed
&& t
->c_ispeed
!= t
->c_ospeed
))
762 /* XXXX handle parity, character size, stop bits, flow control */
767 tp
->t_ispeed
= t
->c_ispeed
;
768 tp
->t_ospeed
= t
->c_ospeed
;
774 scc
->imask
|= (0x2 << ((unit
& 1) * 4)) | 0x80;
775 scc
->sc_regs
->du_imr
= scc
->imask
;
776 #if defined(DEBUG) && 0
777 printf("mfcsparam: speed %d => %x ct %d imask %x cflag %x\n",
778 t
->c_ospeed
, ospeed
, scc
->ct_val
, scc
->imask
, cflag
);
781 (void)mfcsmctl(tp
->t_dev
, 0, DMSET
); /* hang up line */
785 * and set baud rate. (8 bit mode)
787 (void)mfcsmctl(tp
->t_dev
, TIOCM_DTR
| TIOCM_RTS
, DMSET
);
788 sc
->sc_duart
->ch_csr
= ospeed
;
794 mfcshwiflow(struct tty
*tp
, int flag
)
796 struct mfcs_softc
*sc
= device_lookup_private(&mfcs_cd
, tp
->t_dev
& 31);
797 int unit
= tp
->t_dev
& 1;
800 sc
->sc_regs
->du_btrst
= 1 << unit
;
802 sc
->sc_regs
->du_btst
= 1 << unit
;
807 mfcsstart(struct tty
*tp
)
810 struct mfcs_softc
*sc
= device_lookup_private(&mfcs_cd
, tp
->t_dev
& 31);
811 struct mfc_softc
*scc
= sc
->sc_mfc
;
813 if ((tp
->t_state
& TS_ISOPEN
) == 0)
816 unit
= tp
->t_dev
& 1;
819 if (tp
->t_state
& (TS_TIMEOUT
| TS_TTSTOP
))
822 cc
= tp
->t_outq
.c_cc
;
823 if (!ttypull(tp
) || (tp
->t_state
& TS_BUSY
))
827 * We only do bulk transfers if using CTSRTS flow control, not for
828 * (probably sloooow) ixon/ixoff devices.
830 if ((tp
->t_cflag
& CRTSCTS
) == 0)
834 * Limit the amount of output we do in one burst
835 * to prevent hogging the CPU.
837 if (cc
> SEROBUF_SIZE
)
839 cc
= q_to_b(&tp
->t_outq
, sc
->outbuf
, cc
);
841 tp
->t_state
|= TS_BUSY
;
843 sc
->ptr
= sc
->outbuf
;
844 sc
->end
= sc
->outbuf
+ cc
;
847 * Get first character out, then have TBE-interrupts blow out
848 * further characters, until buffer is empty, and TS_BUSY gets
851 sc
->sc_duart
->ch_tb
= *sc
->ptr
++;
852 scc
->imask
|= 1 << (unit
* 4);
853 sc
->sc_regs
->du_imr
= scc
->imask
;
860 * Stop output on a line.
864 mfcsstop(struct tty
*tp
, int flag
)
869 if (tp
->t_state
& TS_BUSY
) {
870 if ((tp
->t_state
& TS_TTSTOP
) == 0)
871 tp
->t_state
|= TS_FLUSH
;
877 mfcsmctl(dev_t dev
, int bits
, int how
)
881 struct mfcs_softc
*sc
= device_lookup_private(&mfcs_cd
, dev
& 31);
886 * convert TIOCM* mask into CIA mask
887 * which is active low
891 * need to save current state of DTR & RTS ?
893 if (bits
& TIOCM_DTR
)
895 if (bits
& TIOCM_RTS
)
901 sc
->sc_regs
->du_btst
= ub
;
902 sc
->sc_regs
->du_btrst
= ub
^ (0x05 << unit
);
906 sc
->sc_regs
->du_btrst
= ub
;
907 ub
= ~sc
->sc_regs
->du_ip
;
911 sc
->sc_regs
->du_btst
= ub
;
912 ub
= ~sc
->sc_regs
->du_ip
;
916 ub
= ~sc
->sc_regs
->du_ip
;
921 /* XXXX should keep DTR & RTS states in softc? */
922 bits
= TIOCM_DTR
| TIOCM_RTS
;
923 if (ub
& (1 << unit
))
925 if (ub
& (4 << unit
))
927 if (ub
& (0x10 << unit
))
929 /* XXXX RI is not supported on all boards */
930 if (sc
->sc_regs
->pad26
& (1 << unit
))
937 * Level 6 interrupt processing for the MultiFaceCard 68681 DUART
943 struct mfc_softc
*scc
= arg
;
944 struct mfcs_softc
*sc
;
945 struct mfc_regs
*regs
;
951 istat
= regs
->du_isr
& scc
->imask
;
954 unit
= device_unit(&scc
->sc_dev
) * 2;
955 if (istat
& 0x02) { /* channel A receive interrupt */
956 sc
= device_lookup_private(&mfcs_cd
, unit
);
958 c
= regs
->du_sra
<< 8;
959 if ((c
& 0x0100) == 0)
962 if (sc
->incnt
== SERIBUF_SIZE
)
966 if (sc
->wptr
== sc
->inbuf
+ SERIBUF_SIZE
)
967 sc
->wptr
= sc
->inbuf
;
969 if (sc
->incnt
> SERIBUF_SIZE
- 16)
976 if (istat
& 0x20) { /* channel B receive interrupt */
977 sc
= device_lookup_private(&mfcs_cd
, unit
+ 1);
979 c
= regs
->du_srb
<< 8;
980 if ((c
& 0x0100) == 0)
983 if (sc
->incnt
== SERIBUF_SIZE
)
987 if (sc
->wptr
== sc
->inbuf
+ SERIBUF_SIZE
)
988 sc
->wptr
= sc
->inbuf
;
990 if (sc
->incnt
> SERIBUF_SIZE
- 16)
997 if (istat
& 0x01) { /* channel A transmit interrupt */
998 sc
= device_lookup_private(&mfcs_cd
, unit
);
1000 if (sc
->ptr
== sc
->end
) {
1001 tp
->t_state
&= ~(TS_BUSY
| TS_FLUSH
);
1002 scc
->imask
&= ~0x01;
1003 regs
->du_imr
= scc
->imask
;
1004 softint_schedule(sc
->mfcs_si
);
1007 regs
->du_tba
= *sc
->ptr
++;
1009 if (istat
& 0x10) { /* channel B transmit interrupt */
1010 sc
= device_lookup_private(&mfcs_cd
, unit
+ 1);
1012 if (sc
->ptr
== sc
->end
) {
1013 tp
->t_state
&= ~(TS_BUSY
| TS_FLUSH
);
1014 scc
->imask
&= ~0x10;
1015 regs
->du_imr
= scc
->imask
;
1016 softint_schedule(sc
->mfcs_si
);
1019 regs
->du_tbb
= *sc
->ptr
++;
1021 if (istat
& 0x80) { /* input port change interrupt */
1023 printf ("%s: ipcr %02x", scc
->sc_dev
.dv_xname
, c
);
1032 struct mfcs_softc
*sc
= device_lookup_private(&mfcs_cd
, unit
);
1033 struct tty
*tp
= sc
->sc_tty
;
1036 * Make sure we're not interrupted by another
1037 * vbl, but allow level6 ints
1042 * pass along any acumulated information
1043 * while input is not blocked
1045 while (sc
->incnt
&& (tp
->t_state
& TS_TBLOCK
) == 0) {
1047 * no collision with ser_fastint()
1049 mfcseint(unit
, *sc
->rptr
++);
1052 /* lock against mfcs_fastint() */
1055 if (sc
->rptr
== sc
->inbuf
+ SERIBUF_SIZE
)
1056 sc
->rptr
= sc
->inbuf
;
1057 if (sc
->ovfl
!= 0) {
1063 log(LOG_WARNING
, "%s: %d buffer overflow!\n",
1064 sc
->sc_dev
.dv_xname
, ovfl
);
1066 if (sc
->incnt
== 0 && (tp
->t_state
& TS_TBLOCK
) == 0) {
1067 sc
->sc_regs
->du_btst
= 1 << unit
; /* XXXX */
1073 mfcseint(int unit
, int stat
)
1075 struct mfcs_softc
*sc
= device_lookup_private(&mfcs_cd
, unit
);
1084 if ((tp
->t_state
& TS_ISOPEN
) == 0) {
1086 extern const struct cdevsw ser_cdevsw
;
1089 /* we don't care about parity errors */
1090 maj
= cdevsw_lookup_major(&ser_cdevsw
);
1091 if (kgdb_dev
== makedev(maj
, unit
) && c
== FRAME_END
)
1092 kgdb_connect(0); /* trap into kgdb */
1098 * Check for break and (if enabled) parity error.
1102 else if (stat
& 0x2000)
1106 log(LOG_WARNING
, "%s: fifo overflow\n",
1107 device_xname(device_lookup_private(&mfcs_cd
, unit
)));
1109 tp
->t_linesw
->l_rint(c
, tp
);
1113 * This interrupt is periodically invoked in the vertical blank
1114 * interrupt. It's used to keep track of the modem control lines
1115 * and (new with the fast_int code) to move accumulated data
1116 * up into the tty layer.
1122 struct mfcs_softc
*sc
= device_lookup_private(&mfcs_cd
, unit
);
1123 u_char stat
, last
, istat
;
1129 if ((tp
->t_state
& TS_ISOPEN
) == 0 && tp
->t_wopen
== 0) {
1130 sc
->rptr
= sc
->wptr
= sc
->inbuf
;
1139 stat
= ~sc
->sc_regs
->du_ip
;
1140 last
= sc
->sc_mfc
->last_ip
;
1141 sc
->sc_mfc
->last_ip
= stat
;
1144 * check whether any interesting signal changed state
1146 istat
= stat
^ last
;
1148 if ((istat
& (0x10 << (unit
& 1))) && /* CD changed */
1149 (SWFLAGS(tp
->t_dev
) & TIOCFLAG_SOFTCAR
) == 0) {
1150 if (stat
& (0x10 << (unit
& 1)))
1151 tp
->t_linesw
->l_modem(tp
, 1);
1152 else if (tp
->t_linesw
->l_modem(tp
, 0) == 0) {
1153 sc
->sc_regs
->du_btrst
= 0x0a << (unit
& 1);
1159 mfcs_intr_soft(void *arg
)
1161 struct mfcs_softc
*sc
= (struct mfcs_softc
*)arg
;
1162 struct tty
*tp
= sc
->sc_tty
;
1165 tp
->t_linesw
->l_start(tp
);