1*169d2b43Sriastradh /* $NetBSD: qvaux.c,v 1.5 2022/10/27 00:00:25 riastradh Exp $ */
2e95f8d8cSmatt
3e95f8d8cSmatt /*-
4e95f8d8cSmatt * Copyright (c) 2015 The NetBSD Foundation, Inc.
5e95f8d8cSmatt * All rights reserved.
6e95f8d8cSmatt *
7e95f8d8cSmatt * This code is derived from software contributed to The NetBSD Foundation
8e95f8d8cSmatt * by Charles H. Dickman
9e95f8d8cSmatt *
10e95f8d8cSmatt * Redistribution and use in source and binary forms, with or without
11e95f8d8cSmatt * modification, are permitted provided that the following conditions
12e95f8d8cSmatt * are met:
13e95f8d8cSmatt * 1. Redistributions of source code must retain the above copyright
14e95f8d8cSmatt * notice, this list of conditions and the following disclaimer.
15e95f8d8cSmatt * 2. Redistributions in binary form must reproduce the above copyright
16e95f8d8cSmatt * notice, this list of conditions and the following disclaimer in the
17e95f8d8cSmatt * documentation and/or other materials provided with the distribution.
18e95f8d8cSmatt *
19e95f8d8cSmatt * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20e95f8d8cSmatt * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21e95f8d8cSmatt * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22e95f8d8cSmatt * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23e95f8d8cSmatt * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24e95f8d8cSmatt * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25e95f8d8cSmatt * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26e95f8d8cSmatt * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27e95f8d8cSmatt * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28e95f8d8cSmatt * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29e95f8d8cSmatt * POSSIBILITY OF SUCH DAMAGE.
30e95f8d8cSmatt */
31e95f8d8cSmatt
32e95f8d8cSmatt /*
33e95f8d8cSmatt * Copyright (c) 1992, 1993
34e95f8d8cSmatt * The Regents of the University of California. All rights reserved.
35e95f8d8cSmatt *
36e95f8d8cSmatt * This code is derived from software contributed to Berkeley by
37e95f8d8cSmatt * Ralph Campbell and Rick Macklem.
38e95f8d8cSmatt *
39e95f8d8cSmatt * Redistribution and use in source and binary forms, with or without
40e95f8d8cSmatt * modification, are permitted provided that the following conditions
41e95f8d8cSmatt * are met:
42e95f8d8cSmatt * 1. Redistributions of source code must retain the above copyright
43e95f8d8cSmatt * notice, this list of conditions and the following disclaimer.
44e95f8d8cSmatt * 2. Redistributions in binary form must reproduce the above copyright
45e95f8d8cSmatt * notice, this list of conditions and the following disclaimer in the
46e95f8d8cSmatt * documentation and/or other materials provided with the distribution.
47e95f8d8cSmatt * 3. Neither the name of the University nor the names of its contributors
48e95f8d8cSmatt * may be used to endorse or promote products derived from this software
49e95f8d8cSmatt * without specific prior written permission.
50e95f8d8cSmatt *
51e95f8d8cSmatt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52e95f8d8cSmatt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53e95f8d8cSmatt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54e95f8d8cSmatt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55e95f8d8cSmatt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56e95f8d8cSmatt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57e95f8d8cSmatt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58e95f8d8cSmatt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59e95f8d8cSmatt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60e95f8d8cSmatt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61e95f8d8cSmatt * SUCH DAMAGE.
62e95f8d8cSmatt */
63e95f8d8cSmatt
64e95f8d8cSmatt /*
65e95f8d8cSmatt * Copyright (c) 1996 Ken C. Wellsch. All rights reserved.
66e95f8d8cSmatt *
67e95f8d8cSmatt * This code is derived from software contributed to Berkeley by
68e95f8d8cSmatt * Ralph Campbell and Rick Macklem.
69e95f8d8cSmatt *
70e95f8d8cSmatt * Redistribution and use in source and binary forms, with or without
71e95f8d8cSmatt * modification, are permitted provided that the following conditions
72e95f8d8cSmatt * are met:
73e95f8d8cSmatt * 1. Redistributions of source code must retain the above copyright
74e95f8d8cSmatt * notice, this list of conditions and the following disclaimer.
75e95f8d8cSmatt * 2. Redistributions in binary form must reproduce the above copyright
76e95f8d8cSmatt * notice, this list of conditions and the following disclaimer in the
77e95f8d8cSmatt * documentation and/or other materials provided with the distribution.
78e95f8d8cSmatt * 3. All advertising materials mentioning features or use of this software
79e95f8d8cSmatt * must display the following acknowledgement:
80e95f8d8cSmatt * This product includes software developed by the University of
81e95f8d8cSmatt * California, Berkeley and its contributors.
82e95f8d8cSmatt * 4. Neither the name of the University nor the names of its contributors
83e95f8d8cSmatt * may be used to endorse or promote products derived from this software
84e95f8d8cSmatt * without specific prior written permission.
85e95f8d8cSmatt *
86e95f8d8cSmatt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
87e95f8d8cSmatt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
88e95f8d8cSmatt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
89e95f8d8cSmatt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
90e95f8d8cSmatt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
91e95f8d8cSmatt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
92e95f8d8cSmatt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
93e95f8d8cSmatt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
94e95f8d8cSmatt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
95e95f8d8cSmatt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
96e95f8d8cSmatt * SUCH DAMAGE.
97e95f8d8cSmatt */
98e95f8d8cSmatt
99e95f8d8cSmatt #include <sys/cdefs.h>
100e95f8d8cSmatt __KERNEL_RCSID(0, "$$");
101e95f8d8cSmatt
102e95f8d8cSmatt #include <sys/param.h>
103e95f8d8cSmatt #include <sys/systm.h>
104e95f8d8cSmatt #include <sys/callout.h>
105e95f8d8cSmatt #include <sys/ioctl.h>
106e95f8d8cSmatt #include <sys/tty.h>
107e95f8d8cSmatt #include <sys/proc.h>
108e95f8d8cSmatt #include <sys/buf.h>
109e95f8d8cSmatt #include <sys/conf.h>
110e95f8d8cSmatt #include <sys/file.h>
111e95f8d8cSmatt #include <sys/uio.h>
112e95f8d8cSmatt #include <sys/kernel.h>
113e95f8d8cSmatt #include <sys/syslog.h>
114e95f8d8cSmatt #include <sys/device.h>
115e95f8d8cSmatt #include <sys/kauth.h>
116e95f8d8cSmatt
117e95f8d8cSmatt #include <sys/bus.h>
118e95f8d8cSmatt #include <dev/qbus/ubavar.h>
119e95f8d8cSmatt
120e95f8d8cSmatt #include <vax/uba/qvareg.h>
121e95f8d8cSmatt #include <vax/uba/qvavar.h>
122e95f8d8cSmatt #include <vax/uba/qvkbdvar.h>
123e95f8d8cSmatt
124e95f8d8cSmatt #include <dev/cons.h>
125e95f8d8cSmatt #include "qv.h"
126e95f8d8cSmatt #include "qvkbd.h"
127e95f8d8cSmatt #include "qvms.h"
128e95f8d8cSmatt #include "qv_ic.h"
129e95f8d8cSmatt
130e95f8d8cSmatt #define QVAUX_DELAY(x) /* nothing */
131e95f8d8cSmatt #define control inline
132e95f8d8cSmatt
133e95f8d8cSmatt static control uint
qvaux_read1(struct qvaux_softc * sc,u_int off)134e95f8d8cSmatt qvaux_read1(struct qvaux_softc *sc, u_int off)
135e95f8d8cSmatt {
136e95f8d8cSmatt u_int rv;
137e95f8d8cSmatt
138e95f8d8cSmatt rv = bus_space_read_1(sc->sc_iot, sc->sc_ioh, off);
139e95f8d8cSmatt QVAUX_DELAY(1);
140e95f8d8cSmatt return rv;
141e95f8d8cSmatt }
142e95f8d8cSmatt
143e95f8d8cSmatt static control u_int
qvaux_read2(struct qvaux_softc * sc,u_int off)144e95f8d8cSmatt qvaux_read2(struct qvaux_softc *sc, u_int off)
145e95f8d8cSmatt {
146e95f8d8cSmatt u_int rv;
147e95f8d8cSmatt
148e95f8d8cSmatt rv = bus_space_read_2(sc->sc_iot, sc->sc_ioh, off);
149e95f8d8cSmatt QVAUX_DELAY(1);
150e95f8d8cSmatt return rv;
151e95f8d8cSmatt }
152e95f8d8cSmatt
153e95f8d8cSmatt static control void
qvaux_write1(struct qvaux_softc * sc,u_int off,u_int val)154e95f8d8cSmatt qvaux_write1(struct qvaux_softc *sc, u_int off, u_int val)
155e95f8d8cSmatt {
156e95f8d8cSmatt
157e95f8d8cSmatt bus_space_write_1(sc->sc_iot, sc->sc_ioh, off, val);
158e95f8d8cSmatt bus_space_barrier(sc->sc_iot, sc->sc_ioh, sc->sc_qr.qr_firstreg,
159e95f8d8cSmatt sc->sc_qr.qr_winsize, BUS_SPACE_BARRIER_WRITE |
160e95f8d8cSmatt BUS_SPACE_BARRIER_READ);
161e95f8d8cSmatt QVAUX_DELAY(10);
162e95f8d8cSmatt }
163e95f8d8cSmatt
164e95f8d8cSmatt static control void
qvaux_write2(struct qvaux_softc * sc,u_int off,u_int val)165e95f8d8cSmatt qvaux_write2(struct qvaux_softc *sc, u_int off, u_int val)
166e95f8d8cSmatt {
167e95f8d8cSmatt
168e95f8d8cSmatt bus_space_write_2(sc->sc_iot, sc->sc_ioh, off, val);
169e95f8d8cSmatt bus_space_barrier(sc->sc_iot, sc->sc_ioh, sc->sc_qr.qr_firstreg,
170e95f8d8cSmatt sc->sc_qr.qr_winsize, BUS_SPACE_BARRIER_WRITE |
171e95f8d8cSmatt BUS_SPACE_BARRIER_READ);
172e95f8d8cSmatt QVAUX_DELAY(10);
173e95f8d8cSmatt }
174e95f8d8cSmatt
175e95f8d8cSmatt #include "ioconf.h"
176e95f8d8cSmatt
177e95f8d8cSmatt /* Flags used to monitor modem bits, make them understood outside driver */
178e95f8d8cSmatt
179e95f8d8cSmatt #define DML_DTR TIOCM_DTR
180e95f8d8cSmatt #define DML_DCD TIOCM_CD
181e95f8d8cSmatt #define DML_RI TIOCM_RI
182e95f8d8cSmatt #define DML_BRK 0100000 /* no equivalent, we will mask */
183e95f8d8cSmatt
184e95f8d8cSmatt static const struct speedtab qvauxspeedtab[] =
185e95f8d8cSmatt {
186e95f8d8cSmatt { 0, 0 },
187e95f8d8cSmatt { 75, CSR_B75 },
188e95f8d8cSmatt { 110, CSR_B110 },
189e95f8d8cSmatt { 134, CSR_B134 },
190e95f8d8cSmatt { 150, CSR_B150 },
191e95f8d8cSmatt { 300, CSR_B300 },
192e95f8d8cSmatt { 600, CSR_B600 },
193e95f8d8cSmatt { 1200, CSR_B1200 },
194e95f8d8cSmatt { 2000, CSR_B2000 },
195e95f8d8cSmatt { 2400, CSR_B2400 },
196e95f8d8cSmatt { 4800, CSR_B4800 },
197e95f8d8cSmatt { 7200, CSR_B7200 },
198e95f8d8cSmatt { 9600, CSR_B9600 },
199e95f8d8cSmatt { 19200, CSR_B19200 },
200e95f8d8cSmatt { -1, -1 }
201e95f8d8cSmatt };
202e95f8d8cSmatt
203e95f8d8cSmatt int qvaux_match(device_t, cfdata_t, void *);
204e95f8d8cSmatt static void qvaux_attach(device_t , device_t , void *);
205e95f8d8cSmatt static void qvauxstart(struct tty *);
206e95f8d8cSmatt static int qvauxparam(struct tty *, struct termios *);
207e95f8d8cSmatt static unsigned qvauxmctl(struct qvaux_softc *, int, int, int);
208e95f8d8cSmatt //static void qvauxscan(void *);
209e95f8d8cSmatt int qvauxgetc(struct qvaux_linestate *);
210e95f8d8cSmatt void qvauxputc(struct qvaux_linestate *, int);
211e95f8d8cSmatt
212e95f8d8cSmatt static dev_type_open(qvauxopen);
213e95f8d8cSmatt static dev_type_close(qvauxclose);
214e95f8d8cSmatt static dev_type_read(qvauxread);
215e95f8d8cSmatt static dev_type_write(qvauxwrite);
216e95f8d8cSmatt static dev_type_ioctl(qvauxioctl);
217e95f8d8cSmatt static dev_type_stop(qvauxstop);
218e95f8d8cSmatt static dev_type_tty(qvauxtty);
219e95f8d8cSmatt static dev_type_poll(qvauxpoll);
220e95f8d8cSmatt
221e95f8d8cSmatt const struct cdevsw qvaux_cdevsw = {
222e95f8d8cSmatt qvauxopen, qvauxclose, qvauxread, qvauxwrite, qvauxioctl,
223e95f8d8cSmatt qvauxstop, qvauxtty, qvauxpoll, nommap, ttykqfilter, nodiscard, D_TTY
224e95f8d8cSmatt };
225e95f8d8cSmatt
226e95f8d8cSmatt int qvaux_timer; /* true if timer started */
227e95f8d8cSmatt struct callout qvauxscan_ch;
228e95f8d8cSmatt static struct cnm_state qvaux_cnm_state;
229e95f8d8cSmatt
230e95f8d8cSmatt CFATTACH_DECL_NEW(qvaux, sizeof(struct qvaux_softc),
231e95f8d8cSmatt qvaux_match, qvaux_attach, NULL, NULL);
232e95f8d8cSmatt
233e95f8d8cSmatt #if NQVKBD > 0 || NQVMS > 0
234e95f8d8cSmatt static int
qvaux_print(void * aux,const char * name)235e95f8d8cSmatt qvaux_print(void *aux, const char *name)
236e95f8d8cSmatt {
237e95f8d8cSmatt struct qvauxkm_attach_args *daa = aux;
238e95f8d8cSmatt if (name == NULL) {
239e95f8d8cSmatt aprint_normal(" line %d", daa->daa_line);
240e95f8d8cSmatt }
241e95f8d8cSmatt
242e95f8d8cSmatt return QUIET;
243e95f8d8cSmatt }
244e95f8d8cSmatt #endif
245e95f8d8cSmatt
246e95f8d8cSmatt int
qvaux_match(device_t parent,cfdata_t match,void * aux)247e95f8d8cSmatt qvaux_match(device_t parent, cfdata_t match, void *aux)
248e95f8d8cSmatt {
249e95f8d8cSmatt /* always match since we are physically part of parent */
250e95f8d8cSmatt return 1;
251e95f8d8cSmatt }
252e95f8d8cSmatt
253e95f8d8cSmatt /*ARGSUSED*/
254e95f8d8cSmatt static void
qvaux_attach(device_t parent,device_t self,void * aux)255e95f8d8cSmatt qvaux_attach(device_t parent, device_t self, void *aux)
256e95f8d8cSmatt {
257e95f8d8cSmatt struct qvaux_softc *sc = device_private(self);
258e95f8d8cSmatt struct uba_attach_args *ua = aux;
259e95f8d8cSmatt #if NQVKBD > 0 || NQVMS > 0
260e95f8d8cSmatt struct qvauxkm_attach_args daa;
261e95f8d8cSmatt #endif
262e95f8d8cSmatt
263e95f8d8cSmatt /* set floating DUART vector and enable interrupts */
264e95f8d8cSmatt qv_ic_setvec(ua, QVA_QVIC, QV_DUART_VEC, ua->ua_cvec);
265e95f8d8cSmatt qv_ic_arm(ua, QVA_QVIC, QV_IC_ENA);
266e95f8d8cSmatt bus_space_write_2(ua->ua_iot, ua->ua_ioh, QVA_QVCSR,
267e95f8d8cSmatt bus_space_read_2(ua->ua_iot, ua->ua_ioh, QVA_QVCSR) | (1 << 6));
268e95f8d8cSmatt
269e95f8d8cSmatt sc->sc_dev = self;
270e95f8d8cSmatt sc->sc_iot = ua->ua_iot;
271e95f8d8cSmatt sc->sc_ioh = ua->ua_ioh;
272e95f8d8cSmatt
273e95f8d8cSmatt /* device register access structure */
274e95f8d8cSmatt sc->sc_qr.qr_ipcr = DU_IPCR;
275e95f8d8cSmatt sc->sc_qr.qr_acr = DU_ACR;
276e95f8d8cSmatt sc->sc_qr.qr_isr = DU_ISR;
277e95f8d8cSmatt sc->sc_qr. qr_imr = DU_IMR;
278e95f8d8cSmatt sc->sc_qr.qr_ctur = DU_CTUR;
279e95f8d8cSmatt sc->sc_qr.qr_ctlr = DU_CTLR;
280e95f8d8cSmatt sc->sc_qr.qr_ip = DU_IP;
281e95f8d8cSmatt sc->sc_qr.qr_opcr = DU_OPCR;
282e95f8d8cSmatt sc->sc_qr.qr_cstrt = DU_IMR;
283e95f8d8cSmatt sc->sc_qr.qr_opset = DU_OPSET;
284e95f8d8cSmatt sc->sc_qr.qr_cstop = DU_CSTOP;
285e95f8d8cSmatt sc->sc_qr.qr_opclr = DU_OPCLR;
286e95f8d8cSmatt sc->sc_qr.qr_ch_regs[0].qr_mr = CH_MR(0);
287e95f8d8cSmatt sc->sc_qr.qr_ch_regs[0].qr_sr = CH_SR(0);
288e95f8d8cSmatt sc->sc_qr.qr_ch_regs[0].qr_csr = CH_CSR(0);
289e95f8d8cSmatt sc->sc_qr.qr_ch_regs[0].qr_cr = CH_CR(0);
290e95f8d8cSmatt sc->sc_qr.qr_ch_regs[0].qr_dat = CH_DAT(0);
291e95f8d8cSmatt sc->sc_qr.qr_ch_regs[1].qr_mr = CH_MR(1);
292e95f8d8cSmatt sc->sc_qr.qr_ch_regs[1].qr_sr = CH_SR(1);
293e95f8d8cSmatt sc->sc_qr.qr_ch_regs[1].qr_csr = CH_CSR(1);
294e95f8d8cSmatt sc->sc_qr.qr_ch_regs[1].qr_cr = CH_CR(1);
295e95f8d8cSmatt sc->sc_qr.qr_ch_regs[1].qr_dat = CH_DAT(1);
296e95f8d8cSmatt
297e95f8d8cSmatt sc->sc_qr.qr_firstreg = QVA_FIRSTREG;
298e95f8d8cSmatt sc->sc_qr.qr_winsize = QVA_WINSIZE;
299e95f8d8cSmatt
300e95f8d8cSmatt /* register DUART interrupt handler */
301e95f8d8cSmatt uba_intr_establish(ua->ua_icookie, ua->ua_cvec,
302e95f8d8cSmatt qvauxint, sc, &sc->sc_tintrcnt);
303e95f8d8cSmatt qv_ic_enable(ua, QVA_QVIC, QV_DUART_VEC, QV_IC_ENA);
304e95f8d8cSmatt
305e95f8d8cSmatt qvauxattach(sc, ua->ua_evcnt, -1);
306e95f8d8cSmatt
307e95f8d8cSmatt #if NQVKBD > 0
308e95f8d8cSmatt /* XXX set line parameters */
309e95f8d8cSmatt qvaux_write2(sc, sc->sc_qr.qr_ch_regs[0].qr_csr,
310e95f8d8cSmatt (CSR_B4800 << 4) | CSR_B4800);
311e95f8d8cSmatt qvaux_write2(sc, sc->sc_qr.qr_ch_regs[0].qr_cr, CR_CMD_MR1 | CR_ENA_RX);
312e95f8d8cSmatt qvaux_write2(sc, sc->sc_qr.qr_ch_regs[0].qr_mr, MR1_CS8 | MR1_PNONE);
313e95f8d8cSmatt qvaux_write2(sc, sc->sc_qr.qr_ch_regs[0].qr_mr, MR2_STOP1);
314e95f8d8cSmatt
315e95f8d8cSmatt daa.daa_line = 0;
316e95f8d8cSmatt daa.daa_flags = 0;
317c7fb772bSthorpej config_found(self, &daa, qvaux_print, CFARGS_NONE);
318e95f8d8cSmatt #endif
319e95f8d8cSmatt #if NQVMS > 0
320e95f8d8cSmatt /* XXX set line parameters */
321e95f8d8cSmatt qvaux_write2(sc, sc->sc_qr.qr_ch_regs[1].qr_csr,
322e95f8d8cSmatt (CSR_B4800 << 4) | CSR_B4800);
323e95f8d8cSmatt qvaux_write2(sc, sc->sc_qr.qr_ch_regs[1].qr_cr, CR_CMD_MR1 | CR_ENA_RX);
324e95f8d8cSmatt qvaux_write2(sc, sc->sc_qr.qr_ch_regs[1].qr_mr, MR1_CS8 | MR1_PODD);
325e95f8d8cSmatt qvaux_write2(sc, sc->sc_qr.qr_ch_regs[1].qr_mr, MR2_STOP1);
326e95f8d8cSmatt
327e95f8d8cSmatt daa.daa_line = 1;
328e95f8d8cSmatt daa.daa_flags = 0;
329c7fb772bSthorpej config_found(self, &daa, qvaux_print, CFARGS_NONE);
330e95f8d8cSmatt #endif
331e95f8d8cSmatt
332e95f8d8cSmatt }
333e95f8d8cSmatt
334e95f8d8cSmatt void
qvauxattach(struct qvaux_softc * sc,struct evcnt * parent_evcnt,int consline)335e95f8d8cSmatt qvauxattach(struct qvaux_softc *sc, struct evcnt *parent_evcnt, int consline)
336e95f8d8cSmatt {
337e95f8d8cSmatt int n;
338e95f8d8cSmatt dev_t dev;
339e95f8d8cSmatt
340e95f8d8cSmatt /* Initialize our softc structure. */
341e95f8d8cSmatt for (n = 0; n < NQVAUXLINE; n++) {
342e95f8d8cSmatt sc->sc_qvaux[n].qvaux_sc = sc;
343e95f8d8cSmatt sc->sc_qvaux[n].qvaux_line = n;
344e95f8d8cSmatt sc->sc_qvaux[n].qvaux_tty = tty_alloc();
345e95f8d8cSmatt dev = sc->sc_qvaux[n].qvaux_tty->t_dev;
346e95f8d8cSmatt sc->sc_qvaux[n].qvaux_tty->t_dev = makedev(major(dev),n);
347e95f8d8cSmatt }
348e95f8d8cSmatt
349e95f8d8cSmatt evcnt_attach_dynamic(&sc->sc_rintrcnt, EVCNT_TYPE_INTR, parent_evcnt,
350e95f8d8cSmatt device_xname(sc->sc_dev), "rintr");
351e95f8d8cSmatt evcnt_attach_dynamic(&sc->sc_tintrcnt, EVCNT_TYPE_INTR, parent_evcnt,
352e95f8d8cSmatt device_xname(sc->sc_dev), "tintr");
353e95f8d8cSmatt
354e95f8d8cSmatt /* Console magic keys */
355e95f8d8cSmatt cn_init_magic(&qvaux_cnm_state);
356e95f8d8cSmatt cn_set_magic("\047\001"); /* default magic is BREAK */
357e95f8d8cSmatt /* VAX will change it in MD code */
358e95f8d8cSmatt
359e95f8d8cSmatt sc->sc_rxint = sc->sc_brk = 0;
360e95f8d8cSmatt sc->sc_consline = consline;
361e95f8d8cSmatt
362e95f8d8cSmatt sc->sc_imr = INT_RXA | INT_RXB;
363e95f8d8cSmatt qvaux_write2(sc, sc->sc_qr.qr_imr, sc->sc_imr);
364e95f8d8cSmatt qvaux_write2(sc, sc->sc_qr.qr_ch_regs[0].qr_cr, CR_ENA_TX | CR_ENA_RX);
365e95f8d8cSmatt qvaux_write2(sc, sc->sc_qr.qr_ch_regs[1].qr_cr, CR_ENA_TX | CR_ENA_RX);
366e95f8d8cSmatt
367e95f8d8cSmatt DELAY(10000);
368e95f8d8cSmatt
369e95f8d8cSmatt printf("\n");
370e95f8d8cSmatt }
371e95f8d8cSmatt
372e95f8d8cSmatt /* DUART Interrupt entry */
373e95f8d8cSmatt
374e95f8d8cSmatt void
qvauxint(void * arg)375e95f8d8cSmatt qvauxint(void *arg)
376e95f8d8cSmatt {
377e95f8d8cSmatt struct qvaux_softc *sc = arg;
378e95f8d8cSmatt int isr;
379e95f8d8cSmatt
380e95f8d8cSmatt isr = qvaux_read2(sc, sc->sc_qr.qr_isr);
381e95f8d8cSmatt
382e95f8d8cSmatt if (isr & (INT_RXA | INT_RXB | INT_BRKA | INT_BRKB))
383e95f8d8cSmatt qvauxrint(arg);
384e95f8d8cSmatt
385e95f8d8cSmatt isr = qvaux_read2(sc, sc->sc_qr.qr_isr);
386e95f8d8cSmatt
387e95f8d8cSmatt if (isr & (INT_TXA | INT_TXB) & sc->sc_imr)
388e95f8d8cSmatt qvauxxint(arg);
389e95f8d8cSmatt }
390e95f8d8cSmatt
391e95f8d8cSmatt /* Receiver Interrupt */
392e95f8d8cSmatt
393e95f8d8cSmatt void
qvauxrint(void * arg)394e95f8d8cSmatt qvauxrint(void *arg)
395e95f8d8cSmatt {
396e95f8d8cSmatt struct qvaux_softc *sc = arg;
397e95f8d8cSmatt struct tty *tp;
398e95f8d8cSmatt int cc, mcc, line;
399e95f8d8cSmatt unsigned stat[2];
400e95f8d8cSmatt int overrun = 0;
401e95f8d8cSmatt
402e95f8d8cSmatt //printf(" qvauxrint ");
403e95f8d8cSmatt
404e95f8d8cSmatt sc->sc_rxint++;
405e95f8d8cSmatt
406e95f8d8cSmatt // determine source and loop until all are no longer active
407e95f8d8cSmatt for (;;) {
408e95f8d8cSmatt stat[0] = qvaux_read2(sc, sc->sc_qr.qr_ch_regs[0].qr_sr);
409e95f8d8cSmatt stat[1] = qvaux_read2(sc, sc->sc_qr.qr_ch_regs[1].qr_sr);
410e95f8d8cSmatt if ((stat[0] & SR_RX_RDY) == 0) {
411e95f8d8cSmatt if ((stat[1] & SR_RX_RDY) == 0)
412e95f8d8cSmatt break;
413e95f8d8cSmatt else
414e95f8d8cSmatt line = 1;
415e95f8d8cSmatt }
416e95f8d8cSmatt else
417e95f8d8cSmatt line = 0;
418e95f8d8cSmatt cc = qvaux_read2(sc, sc->sc_qr.qr_ch_regs[line].qr_dat) & 0xFF;
419e95f8d8cSmatt tp = sc->sc_qvaux[line].qvaux_tty;
420e95f8d8cSmatt
421e95f8d8cSmatt /* Must be caught early */
422e95f8d8cSmatt if (sc->sc_qvaux[line].qvaux_catch &&
423e95f8d8cSmatt (*sc->sc_qvaux[line].qvaux_catch)(sc->sc_qvaux[line]
424e95f8d8cSmatt .qvaux_private, cc)) {
425e95f8d8cSmatt continue;
426e95f8d8cSmatt }
427e95f8d8cSmatt
428e95f8d8cSmatt if (stat[line] & SR_BREAK) // do SR error bits need to be
429e95f8d8cSmatt // cleared by an error reset?
430e95f8d8cSmatt mcc = CNC_BREAK;
431e95f8d8cSmatt else
432e95f8d8cSmatt mcc = cc;
433e95f8d8cSmatt
434e95f8d8cSmatt cn_check_magic(tp->t_dev, mcc, qvaux_cnm_state);
435e95f8d8cSmatt
436e95f8d8cSmatt if (!(tp->t_state & TS_ISOPEN)) {
437e95f8d8cSmatt cv_broadcast(&tp->t_rawcv);
438e95f8d8cSmatt continue;
439e95f8d8cSmatt }
440e95f8d8cSmatt
441e95f8d8cSmatt if ((stat[line] & SR_OVERRUN) && overrun == 0) { // ?
442e95f8d8cSmatt log(LOG_WARNING, "%s: silo overflow, line %d\n",
443e95f8d8cSmatt device_xname(sc->sc_dev), line);
444e95f8d8cSmatt overrun = 1;
445e95f8d8cSmatt }
446e95f8d8cSmatt
447e95f8d8cSmatt if (stat[line] & SR_FRAME) // ?
448e95f8d8cSmatt cc |= TTY_FE;
449e95f8d8cSmatt if (stat[line] & SR_PARITY) // ?
450e95f8d8cSmatt cc |= TTY_PE;
451e95f8d8cSmatt
452e95f8d8cSmatt (*tp->t_linesw->l_rint)(cc, tp);
453e95f8d8cSmatt }
454e95f8d8cSmatt }
455e95f8d8cSmatt
456e95f8d8cSmatt /* Transmitter Interrupt */
457e95f8d8cSmatt
458e95f8d8cSmatt void
qvauxxint(void * arg)459e95f8d8cSmatt qvauxxint(void *arg)
460e95f8d8cSmatt {
461e95f8d8cSmatt struct qvaux_softc *sc = arg;
462e95f8d8cSmatt struct tty *tp;
463e95f8d8cSmatt struct clist *cl;
464e95f8d8cSmatt int line, ch, stat[2];
465e95f8d8cSmatt
466e95f8d8cSmatt for (;;) {
467e95f8d8cSmatt stat[0] = qvaux_read2(sc, sc->sc_qr.qr_ch_regs[0].qr_sr);
468e95f8d8cSmatt stat[1] = qvaux_read2(sc, sc->sc_qr.qr_ch_regs[1].qr_sr);
469e95f8d8cSmatt if (((stat[0] & SR_TX_RDY) == 0)
470e95f8d8cSmatt || ((sc->sc_imr & INT_TXA) == 0)) {
471e95f8d8cSmatt if (((stat[1] & SR_TX_RDY) == 0)
472e95f8d8cSmatt || ((sc->sc_imr & INT_TXB) == 0))
473e95f8d8cSmatt break;
474e95f8d8cSmatt else
475e95f8d8cSmatt line = 1;
476e95f8d8cSmatt }
477e95f8d8cSmatt else
478e95f8d8cSmatt line = 0;
479e95f8d8cSmatt tp = sc->sc_qvaux[line].qvaux_tty;
480e95f8d8cSmatt cl = &tp->t_outq;
481e95f8d8cSmatt tp->t_state &= ~TS_BUSY;
482e95f8d8cSmatt
483e95f8d8cSmatt /* Just send out a char if we have one */
484e95f8d8cSmatt /* As long as we can fill the chip buffer, we just loop here */
485e95f8d8cSmatt // no fifo, just holding register
486e95f8d8cSmatt if (cl->c_cc) {
487e95f8d8cSmatt tp->t_state |= TS_BUSY;
488e95f8d8cSmatt ch = getc(cl);
489e95f8d8cSmatt qvaux_write1(sc, sc->sc_qr.qr_ch_regs[line].qr_dat, ch);
490e95f8d8cSmatt continue;
491e95f8d8cSmatt }
492e95f8d8cSmatt /* Nothing to send, clear the tx flags */
493e95f8d8cSmatt sc->sc_imr &= ~((line) ? (INT_TXB) : (INT_TXA));
494e95f8d8cSmatt qvaux_write2(sc, sc->sc_qr.qr_imr, sc->sc_imr);
495e95f8d8cSmatt
496e95f8d8cSmatt if (sc->sc_qvaux[line].qvaux_catch)
497e95f8d8cSmatt continue;
498e95f8d8cSmatt
499e95f8d8cSmatt if (tp->t_state & TS_FLUSH)
500e95f8d8cSmatt tp->t_state &= ~TS_FLUSH;
501e95f8d8cSmatt else
502e95f8d8cSmatt ndflush (&tp->t_outq, cl->c_cc);
503e95f8d8cSmatt
504e95f8d8cSmatt (*tp->t_linesw->l_start)(tp);
505e95f8d8cSmatt }
506e95f8d8cSmatt }
507e95f8d8cSmatt
508e95f8d8cSmatt int
qvauxopen(dev_t dev,int flag,int mode,struct lwp * l)509e95f8d8cSmatt qvauxopen(dev_t dev, int flag, int mode, struct lwp *l)
510e95f8d8cSmatt {
511e95f8d8cSmatt const int line = QVA_PORT(minor(dev));
512e95f8d8cSmatt struct qvaux_softc *sc = device_lookup_private(&qvaux_cd,
513e95f8d8cSmatt QVA_I2C(minor(dev))); // only one controller
514e95f8d8cSmatt struct tty *tp;
515e95f8d8cSmatt int error = 0;
516e95f8d8cSmatt
517e95f8d8cSmatt if (sc == NULL || line >= NQVAUXLINE)
518e95f8d8cSmatt return ENXIO;
519e95f8d8cSmatt
520e95f8d8cSmatt /* if some other device is using the line, it's busy */
521e95f8d8cSmatt if (sc->sc_qvaux[line].qvaux_catch)
522e95f8d8cSmatt return EBUSY;
523e95f8d8cSmatt
524e95f8d8cSmatt tp = sc->sc_qvaux[line].qvaux_tty;
525e95f8d8cSmatt if (tp == NULL)
526e95f8d8cSmatt return (ENODEV);
527e95f8d8cSmatt
528e95f8d8cSmatt tp->t_oproc = qvauxstart;
529e95f8d8cSmatt tp->t_param = qvauxparam;
530e95f8d8cSmatt tp->t_dev = dev;
531e95f8d8cSmatt
532e95f8d8cSmatt if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
533e95f8d8cSmatt return (EBUSY);
534e95f8d8cSmatt
535e95f8d8cSmatt if ((tp->t_state & TS_ISOPEN) == 0) {
536e95f8d8cSmatt ttychars(tp);
537e95f8d8cSmatt if (tp->t_ispeed == 0) {
538e95f8d8cSmatt tp->t_iflag = TTYDEF_IFLAG;
539e95f8d8cSmatt tp->t_oflag = TTYDEF_OFLAG;
540e95f8d8cSmatt tp->t_cflag = TTYDEF_CFLAG;
541e95f8d8cSmatt tp->t_lflag = TTYDEF_LFLAG;
542e95f8d8cSmatt tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
543e95f8d8cSmatt }
544e95f8d8cSmatt (void) qvauxparam(tp, &tp->t_termios);
545e95f8d8cSmatt ttsetwater(tp);
546e95f8d8cSmatt }
547e95f8d8cSmatt
548e95f8d8cSmatt /* Use DMBIS and *not* DMSET or else we clobber incoming bits */
549e95f8d8cSmatt if (qvauxmctl(sc, line, DML_DTR, DMBIS) & DML_DCD)
550e95f8d8cSmatt tp->t_state |= TS_CARR_ON;
551*169d2b43Sriastradh ttylock(tp);
552e95f8d8cSmatt while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL) &&
553e95f8d8cSmatt !(tp->t_state & TS_CARR_ON)) {
554e95f8d8cSmatt tp->t_wopen++;
555e95f8d8cSmatt error = ttysleep(tp, &tp->t_rawcv, true, 0);
556e95f8d8cSmatt tp->t_wopen--;
557e95f8d8cSmatt if (error)
558e95f8d8cSmatt break;
559e95f8d8cSmatt }
560*169d2b43Sriastradh ttyunlock(tp);
561e95f8d8cSmatt if (error)
562e95f8d8cSmatt return (error);
563e95f8d8cSmatt return ((*tp->t_linesw->l_open)(dev, tp));
564e95f8d8cSmatt }
565e95f8d8cSmatt
566e95f8d8cSmatt /*ARGSUSED*/
567e95f8d8cSmatt int
qvauxclose(dev_t dev,int flag,int mode,struct lwp * l)568e95f8d8cSmatt qvauxclose(dev_t dev, int flag, int mode, struct lwp *l)
569e95f8d8cSmatt {
570e95f8d8cSmatt const int line = QVA_PORT(minor(dev));
571e95f8d8cSmatt struct qvaux_softc *sc = device_lookup_private(&qvaux_cd,
572e95f8d8cSmatt QVA_I2C(minor(dev))); // only one controller
573e95f8d8cSmatt struct tty *tp = sc->sc_qvaux[line].qvaux_tty;
574e95f8d8cSmatt
575e95f8d8cSmatt (*tp->t_linesw->l_close)(tp, flag);
576e95f8d8cSmatt
577e95f8d8cSmatt /* Make sure a BREAK state is not left enabled. */
578e95f8d8cSmatt (void) qvauxmctl(sc, line, DML_BRK, DMBIC);
579e95f8d8cSmatt
580e95f8d8cSmatt /* Do a hangup if so required. */
581e95f8d8cSmatt if ((tp->t_cflag & HUPCL) || tp->t_wopen || !(tp->t_state & TS_ISOPEN))
582e95f8d8cSmatt (void) qvauxmctl(sc, line, 0, DMSET);
583e95f8d8cSmatt
584e95f8d8cSmatt return ttyclose(tp);
585e95f8d8cSmatt }
586e95f8d8cSmatt
587e95f8d8cSmatt int
qvauxread(dev_t dev,struct uio * uio,int flag)588e95f8d8cSmatt qvauxread(dev_t dev, struct uio *uio, int flag)
589e95f8d8cSmatt {
590e95f8d8cSmatt struct qvaux_softc *sc = device_lookup_private(&qvaux_cd,
591e95f8d8cSmatt QVA_I2C(minor(dev))); // only one controller
592e95f8d8cSmatt struct tty *tp = sc->sc_qvaux[QVA_PORT(minor(dev))].qvaux_tty;
593e95f8d8cSmatt
594e95f8d8cSmatt return ((*tp->t_linesw->l_read)(tp, uio, flag));
595e95f8d8cSmatt }
596e95f8d8cSmatt
597e95f8d8cSmatt int
qvauxwrite(dev_t dev,struct uio * uio,int flag)598e95f8d8cSmatt qvauxwrite(dev_t dev, struct uio *uio, int flag)
599e95f8d8cSmatt {
600e95f8d8cSmatt struct qvaux_softc *sc = device_lookup_private(&qvaux_cd,
601e95f8d8cSmatt QVA_I2C(minor(dev))); // only one controller
602e95f8d8cSmatt struct tty *tp = sc->sc_qvaux[QVA_PORT(minor(dev))].qvaux_tty;
603e95f8d8cSmatt
604e95f8d8cSmatt return ((*tp->t_linesw->l_write)(tp, uio, flag));
605e95f8d8cSmatt }
606e95f8d8cSmatt
607e95f8d8cSmatt int
qvauxpoll(dev_t dev,int events,struct lwp * l)608e95f8d8cSmatt qvauxpoll(dev_t dev, int events, struct lwp *l)
609e95f8d8cSmatt {
610e95f8d8cSmatt struct qvaux_softc *sc = device_lookup_private(&qvaux_cd,
611e95f8d8cSmatt QVA_I2C(minor(dev))); // only one controller
612e95f8d8cSmatt struct tty *tp = sc->sc_qvaux[QVA_PORT(minor(dev))].qvaux_tty;
613e95f8d8cSmatt
614e95f8d8cSmatt return ((*tp->t_linesw->l_poll)(tp, events, l));
615e95f8d8cSmatt }
616e95f8d8cSmatt
617e95f8d8cSmatt /*ARGSUSED*/
618e95f8d8cSmatt int
qvauxioctl(dev_t dev,u_long cmd,void * data,int flag,struct lwp * l)619e95f8d8cSmatt qvauxioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
620e95f8d8cSmatt {
621e95f8d8cSmatt struct qvaux_softc *sc = device_lookup_private(&qvaux_cd,
622e95f8d8cSmatt QVA_I2C(minor(dev))); // only one controller
623e95f8d8cSmatt const int line = QVA_PORT(minor(dev));
624e95f8d8cSmatt struct tty *tp = sc->sc_qvaux[line].qvaux_tty;
625e95f8d8cSmatt int error;
626e95f8d8cSmatt
627e95f8d8cSmatt error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
628e95f8d8cSmatt if (error >= 0)
629e95f8d8cSmatt return (error);
630e95f8d8cSmatt
631e95f8d8cSmatt error = ttioctl(tp, cmd, data, flag, l);
632e95f8d8cSmatt if (error >= 0)
633e95f8d8cSmatt return (error);
634e95f8d8cSmatt
635e95f8d8cSmatt switch (cmd) {
636e95f8d8cSmatt case TIOCSBRK:
637e95f8d8cSmatt (void) qvauxmctl(sc, line, DML_BRK, DMBIS);
638e95f8d8cSmatt break;
639e95f8d8cSmatt
640e95f8d8cSmatt case TIOCCBRK:
641e95f8d8cSmatt (void) qvauxmctl(sc, line, DML_BRK, DMBIC);
642e95f8d8cSmatt break;
643e95f8d8cSmatt
644e95f8d8cSmatt case TIOCSDTR:
645e95f8d8cSmatt (void) qvauxmctl(sc, line, DML_DTR, DMBIS);
646e95f8d8cSmatt break;
647e95f8d8cSmatt
648e95f8d8cSmatt case TIOCCDTR:
649e95f8d8cSmatt (void) qvauxmctl(sc, line, DML_DTR, DMBIC);
650e95f8d8cSmatt break;
651e95f8d8cSmatt
652e95f8d8cSmatt case TIOCMSET:
653e95f8d8cSmatt (void) qvauxmctl(sc, line, *(int *)data, DMSET);
654e95f8d8cSmatt break;
655e95f8d8cSmatt
656e95f8d8cSmatt case TIOCMBIS:
657e95f8d8cSmatt (void) qvauxmctl(sc, line, *(int *)data, DMBIS);
658e95f8d8cSmatt break;
659e95f8d8cSmatt
660e95f8d8cSmatt case TIOCMBIC:
661e95f8d8cSmatt (void) qvauxmctl(sc, line, *(int *)data, DMBIC);
662e95f8d8cSmatt break;
663e95f8d8cSmatt
664e95f8d8cSmatt case TIOCMGET:
665e95f8d8cSmatt *(int *)data = (qvauxmctl(sc, line, 0, DMGET) & ~DML_BRK);
666e95f8d8cSmatt break;
667e95f8d8cSmatt
668e95f8d8cSmatt default:
669e95f8d8cSmatt return (EPASSTHROUGH);
670e95f8d8cSmatt }
671e95f8d8cSmatt return (0);
672e95f8d8cSmatt }
673e95f8d8cSmatt
674e95f8d8cSmatt struct tty *
qvauxtty(dev_t dev)675e95f8d8cSmatt qvauxtty(dev_t dev)
676e95f8d8cSmatt {
677e95f8d8cSmatt struct qvaux_softc *sc = device_lookup_private(&qvaux_cd,
678e95f8d8cSmatt QVA_I2C(minor(dev)));
679e95f8d8cSmatt
680e95f8d8cSmatt return sc->sc_qvaux[QVA_PORT(minor(dev))].qvaux_tty;
681e95f8d8cSmatt }
682e95f8d8cSmatt
683e95f8d8cSmatt /*ARGSUSED*/
684e95f8d8cSmatt void
qvauxstop(struct tty * tp,int flag)685e95f8d8cSmatt qvauxstop(struct tty *tp, int flag)
686e95f8d8cSmatt {
687e95f8d8cSmatt if ((tp->t_state & (TS_BUSY | TS_TTSTOP)) == TS_BUSY)
688e95f8d8cSmatt tp->t_state |= TS_FLUSH;
689e95f8d8cSmatt }
690e95f8d8cSmatt
691e95f8d8cSmatt void
qvauxstart(struct tty * tp)692e95f8d8cSmatt qvauxstart(struct tty *tp)
693e95f8d8cSmatt {
694e95f8d8cSmatt struct qvaux_softc *sc;
695e95f8d8cSmatt int line;
696e95f8d8cSmatt int s;
697e95f8d8cSmatt
698e95f8d8cSmatt s = spltty();
699e95f8d8cSmatt if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) {
700e95f8d8cSmatt splx(s);
701e95f8d8cSmatt return;
702e95f8d8cSmatt }
703e95f8d8cSmatt if (!ttypull(tp)) {
704e95f8d8cSmatt splx(s);
705e95f8d8cSmatt return;
706e95f8d8cSmatt }
707e95f8d8cSmatt
708e95f8d8cSmatt line = QVA_PORT(minor(tp->t_dev));
709e95f8d8cSmatt sc = device_lookup_private(&qvaux_cd, QVA_I2C(minor(tp->t_dev)));
710e95f8d8cSmatt
711e95f8d8cSmatt tp->t_state |= TS_BUSY;
712e95f8d8cSmatt sc->sc_imr |= ((line) ? (INT_TXB) : (INT_TXA));
713e95f8d8cSmatt qvaux_write2(sc, sc->sc_qr.qr_imr, sc->sc_imr);
714e95f8d8cSmatt qvauxxint(sc);
715e95f8d8cSmatt splx(s);
716e95f8d8cSmatt }
717e95f8d8cSmatt
718e95f8d8cSmatt static int
qvauxparam(struct tty * tp,struct termios * t)719e95f8d8cSmatt qvauxparam(struct tty *tp, struct termios *t)
720e95f8d8cSmatt {
721e95f8d8cSmatt struct qvaux_softc *sc = device_lookup_private(&qvaux_cd,
722e95f8d8cSmatt QVA_I2C(minor(tp->t_dev)));
723e95f8d8cSmatt const int line = QVA_PORT(minor(tp->t_dev));
724e95f8d8cSmatt int cflag = t->c_cflag;
725e95f8d8cSmatt int ispeed = ttspeedtab(t->c_ispeed, qvauxspeedtab);
726e95f8d8cSmatt int ospeed = ttspeedtab(t->c_ospeed, qvauxspeedtab);
727e95f8d8cSmatt unsigned mr1, mr2;
728e95f8d8cSmatt int s;
729e95f8d8cSmatt
730e95f8d8cSmatt
731e95f8d8cSmatt /* check requested parameters */
732e95f8d8cSmatt if (ospeed < 0 || ispeed < 0)
733e95f8d8cSmatt return (EINVAL);
734e95f8d8cSmatt
735e95f8d8cSmatt tp->t_ispeed = t->c_ispeed;
736e95f8d8cSmatt tp->t_ospeed = t->c_ospeed;
737e95f8d8cSmatt tp->t_cflag = cflag;
738e95f8d8cSmatt
739e95f8d8cSmatt if (ospeed == 0) {
740e95f8d8cSmatt (void) qvauxmctl(sc, line, 0, DMSET); /* hang up line */
741e95f8d8cSmatt return (0);
742e95f8d8cSmatt }
743e95f8d8cSmatt
744e95f8d8cSmatt s = spltty();
745e95f8d8cSmatt
746e95f8d8cSmatt /* XXX This is wrong. Flush output or the chip gets very confused. */
747e95f8d8cSmatt //ttywait(tp);
748e95f8d8cSmatt
749e95f8d8cSmatt //lpr = DZ_LPR_RX_ENABLE | ((ispeed&0xF)<<8) | line;
750e95f8d8cSmatt
751e95f8d8cSmatt qvaux_write2(sc, sc->sc_qr.qr_acr, ACR_BRG);
752e95f8d8cSmatt qvaux_write2(sc, sc->sc_qr.qr_ch_regs[line].qr_csr,
753e95f8d8cSmatt (ispeed << 4) | ospeed);
754e95f8d8cSmatt
755e95f8d8cSmatt mr1 = mr2 = 0;
756e95f8d8cSmatt
757e95f8d8cSmatt switch (cflag & CSIZE)
758e95f8d8cSmatt {
759e95f8d8cSmatt case CS5:
760e95f8d8cSmatt mr1 |= MR1_CS5;
761e95f8d8cSmatt break;
762e95f8d8cSmatt case CS6:
763e95f8d8cSmatt mr1 |= MR1_CS6;
764e95f8d8cSmatt break;
765e95f8d8cSmatt case CS7:
766e95f8d8cSmatt mr1 |= MR1_CS7;
767e95f8d8cSmatt break;
768e95f8d8cSmatt default:
769e95f8d8cSmatt mr1 |= MR1_CS8;
770e95f8d8cSmatt break;
771e95f8d8cSmatt }
772e95f8d8cSmatt if (cflag & PARENB) {
773e95f8d8cSmatt if (cflag & PARODD)
774e95f8d8cSmatt mr1 |= MR1_PODD;
775e95f8d8cSmatt else
776e95f8d8cSmatt mr1 |= MR1_PEVEN;
777e95f8d8cSmatt }
778e95f8d8cSmatt else
779e95f8d8cSmatt mr1 |= MR1_PNONE;
780e95f8d8cSmatt if (cflag & CSTOPB)
781e95f8d8cSmatt mr2 |= MR2_STOP2;
782e95f8d8cSmatt else
783e95f8d8cSmatt mr2 |= MR2_STOP1;
784e95f8d8cSmatt
785e95f8d8cSmatt qvaux_write2(sc, sc->sc_qr.qr_ch_regs[line].qr_cr,
786e95f8d8cSmatt CR_CMD_MR1 | CR_ENA_RX); // reset to mr1
787e95f8d8cSmatt qvaux_write2(sc, sc->sc_qr.qr_ch_regs[line].qr_mr, mr1);
788e95f8d8cSmatt qvaux_write2(sc, sc->sc_qr.qr_ch_regs[line].qr_mr, mr2);
789e95f8d8cSmatt qvaux_write2(sc, sc->sc_qr.qr_acr, ACR_BRG);
790e95f8d8cSmatt (void) splx(s);
791e95f8d8cSmatt DELAY(10000);
792e95f8d8cSmatt
793e95f8d8cSmatt return (0);
794e95f8d8cSmatt }
795e95f8d8cSmatt
796e95f8d8cSmatt // QVSS has no modem control signals
797e95f8d8cSmatt static unsigned
qvauxmctl(struct qvaux_softc * sc,int line,int bits,int how)798e95f8d8cSmatt qvauxmctl(struct qvaux_softc *sc, int line, int bits, int how)
799e95f8d8cSmatt {
800e95f8d8cSmatt /* unsigned status; */
801e95f8d8cSmatt unsigned mbits;
802e95f8d8cSmatt unsigned bit;
803e95f8d8cSmatt int s;
804e95f8d8cSmatt
805e95f8d8cSmatt s = spltty();
806e95f8d8cSmatt mbits = 0;
807e95f8d8cSmatt bit = (1 << line);
808e95f8d8cSmatt #if 0
809e95f8d8cSmatt
810e95f8d8cSmatt /* external signals as seen from the port */
811e95f8d8cSmatt status = qvaux_read1(sc, sc->sc_dr.dr_dcd) | sc->sc_dsr;
812e95f8d8cSmatt if (status & bit)
813e95f8d8cSmatt mbits |= DML_DCD;
814e95f8d8cSmatt status = qvaux_read1(sc, sc->sc_dr.dr_ring);
815e95f8d8cSmatt if (status & bit)
816e95f8d8cSmatt mbits |= DML_RI;
817e95f8d8cSmatt
818e95f8d8cSmatt /* internal signals/state delivered to port */
819e95f8d8cSmatt status = qvaux_read1(sc, sc->sc_dr.dr_dtr);
820e95f8d8cSmatt if (status & bit)
821e95f8d8cSmatt mbits |= DML_DTR;
822e95f8d8cSmatt #endif
823e95f8d8cSmatt if (sc->sc_brk & bit)
824e95f8d8cSmatt mbits |= DML_BRK;
825e95f8d8cSmatt
826e95f8d8cSmatt switch (how)
827e95f8d8cSmatt {
828e95f8d8cSmatt case DMSET:
829e95f8d8cSmatt mbits = bits;
830e95f8d8cSmatt break;
831e95f8d8cSmatt
832e95f8d8cSmatt case DMBIS:
833e95f8d8cSmatt mbits |= bits;
834e95f8d8cSmatt break;
835e95f8d8cSmatt
836e95f8d8cSmatt case DMBIC:
837e95f8d8cSmatt mbits &= ~bits;
838e95f8d8cSmatt break;
839e95f8d8cSmatt
840e95f8d8cSmatt case DMGET:
841e95f8d8cSmatt (void) splx(s);
842e95f8d8cSmatt return (mbits);
843e95f8d8cSmatt }
844e95f8d8cSmatt #if 0
845e95f8d8cSmatt if (mbits & DML_DTR) {
846e95f8d8cSmatt qvaux_write1(sc, sc->sc_dr.dr_dtr,
847e95f8d8cSmatt qvaux_read1(sc, sc->sc_dr.dr_dtr) | bit);
848e95f8d8cSmatt } else {
849e95f8d8cSmatt qvaux_write1(sc, sc->sc_dr.dr_dtr,
850e95f8d8cSmatt qvaux_read1(sc, sc->sc_dr.dr_dtr) & ~bit);
851e95f8d8cSmatt }
852e95f8d8cSmatt #endif
853e95f8d8cSmatt if (mbits & DML_BRK) {
854e95f8d8cSmatt sc->sc_brk |= bit;
855e95f8d8cSmatt qvaux_write1(sc, sc->sc_qr.qr_ch_regs[line].qr_cr,
856e95f8d8cSmatt CR_CMD_START_BRK);
857e95f8d8cSmatt } else {
858e95f8d8cSmatt sc->sc_brk &= ~bit;
859e95f8d8cSmatt qvaux_write1(sc, sc->sc_qr.qr_ch_regs[line].qr_cr,
860e95f8d8cSmatt CR_CMD_STOP_BRK);
861e95f8d8cSmatt }
862e95f8d8cSmatt
863e95f8d8cSmatt (void) splx(s);
864e95f8d8cSmatt
865e95f8d8cSmatt return (mbits);
866e95f8d8cSmatt }
867e95f8d8cSmatt
868e95f8d8cSmatt /*
869e95f8d8cSmatt * Called after an ubareset. The QVSS card is reset, but the only thing
870e95f8d8cSmatt * that must be done is to start the receiver and transmitter again.
871e95f8d8cSmatt * No DMA setup to care about.
872e95f8d8cSmatt */
873e95f8d8cSmatt void
qvauxreset(device_t dev)874e95f8d8cSmatt qvauxreset(device_t dev)
875e95f8d8cSmatt {
876e95f8d8cSmatt struct qvaux_softc *sc = device_private(dev);
877e95f8d8cSmatt struct tty *tp;
878e95f8d8cSmatt int i;
879e95f8d8cSmatt
880e95f8d8cSmatt for (i = 0; i < NQVAUXLINE; i++) {
881e95f8d8cSmatt tp = sc->sc_qvaux[i].qvaux_tty;
882e95f8d8cSmatt
883e95f8d8cSmatt if (((tp->t_state & TS_ISOPEN) == 0) || (tp->t_wopen == 0))
884e95f8d8cSmatt continue;
885e95f8d8cSmatt
886e95f8d8cSmatt qvauxparam(tp, &tp->t_termios);
887e95f8d8cSmatt qvauxmctl(sc, i, DML_DTR, DMSET);
888e95f8d8cSmatt tp->t_state &= ~TS_BUSY;
889e95f8d8cSmatt qvauxstart(tp); /* Kick off transmitter again */
890e95f8d8cSmatt }
891e95f8d8cSmatt }
892e95f8d8cSmatt
893e95f8d8cSmatt #if NQVKBD > 0 || NQVMS > 0
894e95f8d8cSmatt int
qvauxgetc(struct qvaux_linestate * ls)895e95f8d8cSmatt qvauxgetc(struct qvaux_linestate *ls)
896e95f8d8cSmatt {
897e95f8d8cSmatt #if 0
898e95f8d8cSmatt int line = ls->qvaux_line;
899e95f8d8cSmatt int s;
900e95f8d8cSmatt u_short rbuf;
901e95f8d8cSmatt
902e95f8d8cSmatt s = spltty();
903e95f8d8cSmatt for (;;) {
904e95f8d8cSmatt for(; (dz->csr & DZ_CSR_RX_DONE) == 0;);
905e95f8d8cSmatt rbuf = dz->rbuf;
906e95f8d8cSmatt if (((rbuf >> 8) & 3) == line) {
907e95f8d8cSmatt splx(s);
908e95f8d8cSmatt return (rbuf & 0xff);
909e95f8d8cSmatt }
910e95f8d8cSmatt }
911e95f8d8cSmatt #endif
912e95f8d8cSmatt return 0;
913e95f8d8cSmatt }
914e95f8d8cSmatt
915e95f8d8cSmatt void
qvauxputc(struct qvaux_linestate * ls,int ch)916e95f8d8cSmatt qvauxputc(struct qvaux_linestate *ls, int ch)
917e95f8d8cSmatt {
918e95f8d8cSmatt //int line;
919e95f8d8cSmatt int s;
920e95f8d8cSmatt
921e95f8d8cSmatt /* if the qvaux has already been attached, the MI
922e95f8d8cSmatt driver will do the transmitting: */
923e95f8d8cSmatt if (ls && ls->qvaux_sc) {
924e95f8d8cSmatt s = spltty();
925e95f8d8cSmatt // line = ls->qvaux_line;
926e95f8d8cSmatt putc(ch, &ls->qvaux_tty->t_outq);
927e95f8d8cSmatt qvauxstart(ls->qvaux_tty);
928e95f8d8cSmatt splx(s);
929e95f8d8cSmatt return;
930e95f8d8cSmatt }
931e95f8d8cSmatt
932e95f8d8cSmatt /* use qvauxcnputc to do the transmitting: */
933e95f8d8cSmatt //qvauxcnputc(makedev(cdevsw_lookup_major(&qvaux_cdevsw), 0), ch);
934e95f8d8cSmatt }
935e95f8d8cSmatt #endif /* NQVKBD > 0 || NQVMS > 0 */
936