dcm.c revision 1.86 1 1.86 dholland /* $NetBSD: dcm.c,v 1.86 2014/05/22 16:31:19 dholland Exp $ */
2 1.42 thorpej
3 1.42 thorpej /*-
4 1.42 thorpej * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
5 1.42 thorpej * All rights reserved.
6 1.42 thorpej *
7 1.42 thorpej * This code is derived from software contributed to The NetBSD Foundation
8 1.42 thorpej * by Jason R. Thorpe.
9 1.42 thorpej *
10 1.42 thorpej * Redistribution and use in source and binary forms, with or without
11 1.42 thorpej * modification, are permitted provided that the following conditions
12 1.42 thorpej * are met:
13 1.42 thorpej * 1. Redistributions of source code must retain the above copyright
14 1.42 thorpej * notice, this list of conditions and the following disclaimer.
15 1.42 thorpej * 2. Redistributions in binary form must reproduce the above copyright
16 1.42 thorpej * notice, this list of conditions and the following disclaimer in the
17 1.42 thorpej * documentation and/or other materials provided with the distribution.
18 1.42 thorpej *
19 1.42 thorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.42 thorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.42 thorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.42 thorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.42 thorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.42 thorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.42 thorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.42 thorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.42 thorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.42 thorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.42 thorpej * POSSIBILITY OF SUCH DAMAGE.
30 1.42 thorpej */
31 1.15 cgd
32 1.1 cgd /*
33 1.82 rmind * Copyright (c) 1988 University of Utah.
34 1.14 mycroft * Copyright (c) 1982, 1986, 1990, 1993
35 1.14 mycroft * The Regents of the University of California. All rights reserved.
36 1.1 cgd *
37 1.1 cgd * This code is derived from software contributed to Berkeley by
38 1.1 cgd * the Systems Programming Group of the University of Utah Computer
39 1.1 cgd * Science Department.
40 1.1 cgd *
41 1.1 cgd * Redistribution and use in source and binary forms, with or without
42 1.1 cgd * modification, are permitted provided that the following conditions
43 1.1 cgd * are met:
44 1.1 cgd * 1. Redistributions of source code must retain the above copyright
45 1.1 cgd * notice, this list of conditions and the following disclaimer.
46 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
47 1.1 cgd * notice, this list of conditions and the following disclaimer in the
48 1.1 cgd * documentation and/or other materials provided with the distribution.
49 1.62 agc * 3. Neither the name of the University nor the names of its contributors
50 1.62 agc * may be used to endorse or promote products derived from this software
51 1.62 agc * without specific prior written permission.
52 1.62 agc *
53 1.62 agc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54 1.62 agc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 1.62 agc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 1.62 agc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57 1.62 agc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 1.62 agc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 1.62 agc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 1.62 agc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 1.62 agc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 1.62 agc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 1.62 agc * SUCH DAMAGE.
64 1.62 agc *
65 1.62 agc * from Utah: $Hdr: dcm.c 1.29 92/01/21$
66 1.62 agc *
67 1.62 agc * @(#)dcm.c 8.4 (Berkeley) 1/12/94
68 1.62 agc */
69 1.1 cgd
70 1.1 cgd /*
71 1.1 cgd * TODO:
72 1.1 cgd * Timeouts
73 1.1 cgd * Test console support.
74 1.1 cgd */
75 1.1 cgd
76 1.1 cgd /*
77 1.1 cgd * 98642/MUX
78 1.1 cgd */
79 1.50 gmcgarry
80 1.50 gmcgarry #include <sys/cdefs.h>
81 1.86 dholland __KERNEL_RCSID(0, "$NetBSD: dcm.c,v 1.86 2014/05/22 16:31:19 dholland Exp $");
82 1.47 lukem
83 1.47 lukem #include "opt_kgdb.h"
84 1.47 lukem
85 1.13 mycroft #include <sys/param.h>
86 1.13 mycroft #include <sys/systm.h>
87 1.13 mycroft #include <sys/ioctl.h>
88 1.13 mycroft #include <sys/proc.h>
89 1.13 mycroft #include <sys/tty.h>
90 1.13 mycroft #include <sys/conf.h>
91 1.13 mycroft #include <sys/file.h>
92 1.13 mycroft #include <sys/uio.h>
93 1.13 mycroft #include <sys/kernel.h>
94 1.13 mycroft #include <sys/syslog.h>
95 1.13 mycroft #include <sys/time.h>
96 1.34 thorpej #include <sys/device.h>
97 1.71 elad #include <sys/kauth.h>
98 1.13 mycroft
99 1.59 gmcgarry #include <machine/bus.h>
100 1.14 mycroft
101 1.22 thorpej #include <dev/cons.h>
102 1.22 thorpej
103 1.34 thorpej #include <hp300/dev/diovar.h>
104 1.34 thorpej #include <hp300/dev/diodevs.h>
105 1.13 mycroft #include <hp300/dev/dcmreg.h>
106 1.1 cgd
107 1.66 tsutsui #include "ioconf.h"
108 1.66 tsutsui
109 1.1 cgd #ifndef DEFAULT_BAUD_RATE
110 1.1 cgd #define DEFAULT_BAUD_RATE 9600
111 1.1 cgd #endif
112 1.1 cgd
113 1.65 thorpej static const struct speedtab dcmspeedtab[] = {
114 1.36 scottr { 0, BR_0 },
115 1.36 scottr { 50, BR_50 },
116 1.36 scottr { 75, BR_75 },
117 1.36 scottr { 110, BR_110 },
118 1.36 scottr { 134, BR_134 },
119 1.36 scottr { 150, BR_150 },
120 1.36 scottr { 300, BR_300 },
121 1.36 scottr { 600, BR_600 },
122 1.36 scottr { 1200, BR_1200 },
123 1.36 scottr { 1800, BR_1800 },
124 1.36 scottr { 2400, BR_2400 },
125 1.36 scottr { 4800, BR_4800 },
126 1.36 scottr { 9600, BR_9600 },
127 1.36 scottr { 19200, BR_19200 },
128 1.36 scottr { 38400, BR_38400 },
129 1.36 scottr { -1, -1 },
130 1.1 cgd };
131 1.1 cgd
132 1.1 cgd /* u-sec per character based on baudrate (assumes 1 start/8 data/1 stop bit) */
133 1.1 cgd #define DCM_USPERCH(s) (10000000 / (s))
134 1.1 cgd
135 1.1 cgd /*
136 1.1 cgd * Per board interrupt scheme. 16.7ms is the polling interrupt rate
137 1.1 cgd * (16.7ms is about 550 baud, 38.4k is 72 chars in 16.7ms).
138 1.1 cgd */
139 1.1 cgd #define DIS_TIMER 0
140 1.1 cgd #define DIS_PERCHAR 1
141 1.1 cgd #define DIS_RESET 2
142 1.1 cgd
143 1.65 thorpej static int dcmistype = -1; /* -1 == dynamic, 0 == timer, 1 == perchar */
144 1.65 thorpej static int dcminterval = 5; /* interval (secs) between checks */
145 1.1 cgd struct dcmischeme {
146 1.1 cgd int dis_perchar; /* non-zero if interrupting per char */
147 1.1 cgd long dis_time; /* last time examined */
148 1.1 cgd int dis_intr; /* recv interrupts during last interval */
149 1.1 cgd int dis_char; /* characters read during last interval */
150 1.20 thorpej };
151 1.1 cgd
152 1.1 cgd #ifdef KGDB
153 1.1 cgd /*
154 1.1 cgd * Kernel GDB support
155 1.1 cgd */
156 1.14 mycroft #include <machine/remote-sl.h>
157 1.1 cgd
158 1.1 cgd extern dev_t kgdb_dev;
159 1.1 cgd extern int kgdb_rate;
160 1.1 cgd extern int kgdb_debug_init;
161 1.1 cgd #endif
162 1.1 cgd
163 1.14 mycroft /* #define DCMSTATS */
164 1.1 cgd
165 1.1 cgd #ifdef DEBUG
166 1.1 cgd int dcmdebug = 0x0;
167 1.1 cgd #define DDB_SIOERR 0x01
168 1.1 cgd #define DDB_PARAM 0x02
169 1.1 cgd #define DDB_INPUT 0x04
170 1.1 cgd #define DDB_OUTPUT 0x08
171 1.1 cgd #define DDB_INTR 0x10
172 1.1 cgd #define DDB_IOCTL 0x20
173 1.1 cgd #define DDB_INTSCHM 0x40
174 1.1 cgd #define DDB_MODEM 0x80
175 1.1 cgd #define DDB_OPENCLOSE 0x100
176 1.1 cgd #endif
177 1.1 cgd
178 1.14 mycroft #ifdef DCMSTATS
179 1.1 cgd #define DCMRBSIZE 94
180 1.1 cgd #define DCMXBSIZE 24
181 1.1 cgd
182 1.1 cgd struct dcmstats {
183 1.1 cgd long xints; /* # of xmit ints */
184 1.1 cgd long xchars; /* # of xmit chars */
185 1.1 cgd long xempty; /* times outq is empty in dcmstart */
186 1.1 cgd long xrestarts; /* times completed while xmitting */
187 1.1 cgd long rints; /* # of recv ints */
188 1.1 cgd long rchars; /* # of recv chars */
189 1.1 cgd long xsilo[DCMXBSIZE+2]; /* times this many chars xmit on one int */
190 1.1 cgd long rsilo[DCMRBSIZE+2]; /* times this many chars read on one int */
191 1.20 thorpej };
192 1.1 cgd #endif
193 1.1 cgd
194 1.44 thorpej #define DCMUNIT(x) (minor(x) & 0x7ffff)
195 1.44 thorpej #define DCMDIALOUT(x) (minor(x) & 0x80000)
196 1.20 thorpej #define DCMBOARD(x) (((x) >> 2) & 0x3f)
197 1.20 thorpej #define DCMPORT(x) ((x) & 3)
198 1.1 cgd
199 1.1 cgd /*
200 1.1 cgd * Conversion from "HP DCE" to almost-normal DCE: on the 638 8-port mux,
201 1.1 cgd * the distribution panel uses "HP DCE" conventions. If requested via
202 1.1 cgd * the device flags, we swap the inputs to something closer to normal DCE,
203 1.1 cgd * allowing a straight-through cable to a DTE or a reversed cable
204 1.1 cgd * to a DCE (reversing 2-3, 4-5, 8-20 and leaving 6 unconnected;
205 1.1 cgd * this gets "DCD" on pin 20 and "CTS" on 4, but doesn't connect
206 1.1 cgd * DSR or make RTS work, though). The following gives the full
207 1.1 cgd * details of a cable from this mux panel to a modem:
208 1.1 cgd *
209 1.1 cgd * HP modem
210 1.1 cgd * name pin pin name
211 1.1 cgd * HP inputs:
212 1.1 cgd * "Rx" 2 3 Tx
213 1.1 cgd * CTS 4 5 CTS (only needed for CCTS_OFLOW)
214 1.1 cgd * DCD 20 8 DCD
215 1.1 cgd * "DSR" 9 6 DSR (unneeded)
216 1.1 cgd * RI 22 22 RI (unneeded)
217 1.1 cgd *
218 1.1 cgd * HP outputs:
219 1.1 cgd * "Tx" 3 2 Rx
220 1.1 cgd * "DTR" 6 not connected
221 1.1 cgd * "RTS" 8 20 DTR
222 1.1 cgd * "SR" 23 4 RTS (often not needed)
223 1.1 cgd */
224 1.1 cgd #define hp2dce_in(ibits) (iconv[(ibits) & 0xf])
225 1.65 thorpej static const char iconv[16] = {
226 1.1 cgd 0, MI_DM, MI_CTS, MI_CTS|MI_DM,
227 1.1 cgd MI_CD, MI_CD|MI_DM, MI_CD|MI_CTS, MI_CD|MI_CTS|MI_DM,
228 1.1 cgd MI_RI, MI_RI|MI_DM, MI_RI|MI_CTS, MI_RI|MI_CTS|MI_DM,
229 1.1 cgd MI_RI|MI_CD, MI_RI|MI_CD|MI_DM, MI_RI|MI_CD|MI_CTS,
230 1.1 cgd MI_RI|MI_CD|MI_CTS|MI_DM
231 1.1 cgd };
232 1.1 cgd
233 1.21 thorpej /*
234 1.21 thorpej * Note that 8-port boards appear as 2 4-port boards at consecutive
235 1.21 thorpej * select codes.
236 1.21 thorpej */
237 1.21 thorpej #define NDCMPORT 4
238 1.20 thorpej
239 1.20 thorpej struct dcm_softc {
240 1.79 tsutsui device_t sc_dev; /* generic device glue */
241 1.59 gmcgarry
242 1.59 gmcgarry bus_space_tag_t sc_bst;
243 1.59 gmcgarry bus_space_handle_t sc_bsh;
244 1.59 gmcgarry
245 1.20 thorpej struct dcmdevice *sc_dcm; /* pointer to hardware */
246 1.20 thorpej struct tty *sc_tty[NDCMPORT]; /* our tty instances */
247 1.20 thorpej struct modemreg *sc_modem[NDCMPORT]; /* modem control */
248 1.20 thorpej char sc_mcndlast[NDCMPORT]; /* XXX last modem status for port */
249 1.20 thorpej short sc_softCAR; /* mask of ports with soft-carrier */
250 1.20 thorpej struct dcmischeme sc_scheme; /* interrupt scheme for board */
251 1.20 thorpej
252 1.20 thorpej /*
253 1.20 thorpej * Mask of soft-carrier bits in config flags.
254 1.20 thorpej */
255 1.20 thorpej #define DCM_SOFTCAR 0x0000000f
256 1.20 thorpej
257 1.20 thorpej int sc_flags; /* misc. configuration info */
258 1.20 thorpej
259 1.20 thorpej /*
260 1.20 thorpej * Bits for sc_flags
261 1.20 thorpej */
262 1.20 thorpej #define DCM_ACTIVE 0x00000001 /* indicates board is alive */
263 1.24 thorpej #define DCM_ISCONSOLE 0x00000002 /* indicates board is console */
264 1.20 thorpej #define DCM_STDDCE 0x00000010 /* re-map DCE to standard */
265 1.20 thorpej #define DCM_FLAGMASK (DCM_STDDCE) /* mask of valid bits in config flags */
266 1.20 thorpej
267 1.20 thorpej #ifdef DCMSTATS
268 1.20 thorpej struct dcmstats sc_stats; /* metrics gathering */
269 1.20 thorpej #endif
270 1.34 thorpej };
271 1.34 thorpej
272 1.65 thorpej static int dcmintr(void *);
273 1.65 thorpej static void dcmpint(struct dcm_softc *, int, int);
274 1.65 thorpej static void dcmrint(struct dcm_softc *);
275 1.65 thorpej static void dcmreadbuf(struct dcm_softc *, int);
276 1.65 thorpej static void dcmxint(struct dcm_softc *, int);
277 1.65 thorpej static void dcmmint(struct dcm_softc *, int, int);
278 1.65 thorpej
279 1.65 thorpej static int dcmparam(struct tty *, struct termios *);
280 1.65 thorpej static void dcmstart(struct tty *);
281 1.65 thorpej static int dcmmctl(dev_t, int, int);
282 1.65 thorpej static void dcmsetischeme(int, int);
283 1.65 thorpej static void dcminit(struct dcmdevice *, int, int);
284 1.65 thorpej
285 1.65 thorpej static int dcmselftest(struct dcm_softc *);
286 1.36 scottr
287 1.65 thorpej static int dcmcngetc(dev_t);
288 1.65 thorpej static void dcmcnputc(dev_t, int);
289 1.65 thorpej
290 1.65 thorpej int dcmcnattach(bus_space_tag_t, bus_addr_t, int);
291 1.65 thorpej
292 1.79 tsutsui static int dcmmatch(device_t, cfdata_t, void *);
293 1.79 tsutsui static void dcmattach(device_t, device_t, void *);
294 1.38 scottr
295 1.79 tsutsui CFATTACH_DECL_NEW(dcm, sizeof(struct dcm_softc),
296 1.54 thorpej dcmmatch, dcmattach, NULL, NULL);
297 1.38 scottr
298 1.48 gmcgarry /*
299 1.48 gmcgarry * Stuff for DCM console support. This could probably be done a little
300 1.48 gmcgarry * better.
301 1.48 gmcgarry */
302 1.48 gmcgarry static struct dcmdevice *dcm_cn = NULL; /* pointer to hardware */
303 1.48 gmcgarry static int dcmconsinit; /* has been initialized */
304 1.79 tsutsui #if 0
305 1.79 tsutsui static int dcm_lastcnpri = CN_DEAD; /* XXX last priority */
306 1.79 tsutsui #endif
307 1.48 gmcgarry
308 1.48 gmcgarry static struct consdev dcm_cons = {
309 1.63 tsutsui NULL,
310 1.63 tsutsui NULL,
311 1.63 tsutsui dcmcngetc,
312 1.63 tsutsui dcmcnputc,
313 1.63 tsutsui nullcnpollc,
314 1.63 tsutsui NULL,
315 1.63 tsutsui NULL,
316 1.63 tsutsui NULL,
317 1.63 tsutsui NODEV,
318 1.63 tsutsui CN_REMOTE
319 1.48 gmcgarry };
320 1.48 gmcgarry int dcmconscode;
321 1.48 gmcgarry int dcmdefaultrate = DEFAULT_BAUD_RATE;
322 1.48 gmcgarry int dcmconbrdbusy = 0;
323 1.48 gmcgarry
324 1.65 thorpej static dev_type_open(dcmopen);
325 1.65 thorpej static dev_type_close(dcmclose);
326 1.65 thorpej static dev_type_read(dcmread);
327 1.65 thorpej static dev_type_write(dcmwrite);
328 1.65 thorpej static dev_type_ioctl(dcmioctl);
329 1.65 thorpej static dev_type_stop(dcmstop);
330 1.65 thorpej static dev_type_tty(dcmtty);
331 1.65 thorpej static dev_type_poll(dcmpoll);
332 1.52 gehenna
333 1.52 gehenna const struct cdevsw dcm_cdevsw = {
334 1.84 dholland .d_open = dcmopen,
335 1.84 dholland .d_close = dcmclose,
336 1.84 dholland .d_read = dcmread,
337 1.84 dholland .d_write = dcmwrite,
338 1.84 dholland .d_ioctl = dcmioctl,
339 1.84 dholland .d_stop = dcmstop,
340 1.84 dholland .d_tty = dcmtty,
341 1.84 dholland .d_poll = dcmpoll,
342 1.84 dholland .d_mmap = nommap,
343 1.84 dholland .d_kqfilter = ttykqfilter,
344 1.84 dholland .d_flag = D_TTY
345 1.52 gehenna };
346 1.52 gehenna
347 1.65 thorpej static int
348 1.79 tsutsui dcmmatch(device_t parent, cfdata_t cf, void *aux)
349 1.34 thorpej {
350 1.34 thorpej struct dio_attach_args *da = aux;
351 1.34 thorpej
352 1.34 thorpej switch (da->da_id) {
353 1.34 thorpej case DIO_DEVICE_ID_DCM:
354 1.34 thorpej case DIO_DEVICE_ID_DCMREM:
355 1.72 tsutsui return 1;
356 1.34 thorpej }
357 1.34 thorpej
358 1.72 tsutsui return 0;
359 1.34 thorpej }
360 1.20 thorpej
361 1.65 thorpej static void
362 1.79 tsutsui dcmattach(device_t parent, device_t self, void *aux)
363 1.34 thorpej {
364 1.79 tsutsui struct dcm_softc *sc = device_private(self);
365 1.34 thorpej struct dio_attach_args *da = aux;
366 1.34 thorpej struct dcmdevice *dcm;
367 1.69 thorpej int brd = device_unit(self);
368 1.34 thorpej int scode = da->da_scode;
369 1.59 gmcgarry int i, mbits, code;
370 1.20 thorpej
371 1.79 tsutsui sc->sc_dev = self;
372 1.36 scottr sc->sc_flags = 0;
373 1.36 scottr
374 1.48 gmcgarry if (scode == dcmconscode) {
375 1.48 gmcgarry dcm = dcm_cn;
376 1.24 thorpej sc->sc_flags |= DCM_ISCONSOLE;
377 1.24 thorpej
378 1.24 thorpej /*
379 1.24 thorpej * We didn't know which unit this would be during
380 1.24 thorpej * the console probe, so we have to fixup cn_dev here.
381 1.24 thorpej * Note that we always assume port 1 on the board.
382 1.24 thorpej */
383 1.52 gehenna cn_tab->cn_dev = makedev(cdevsw_lookup_major(&dcm_cdevsw),
384 1.79 tsutsui (brd << 2) | DCMCONSPORT);
385 1.34 thorpej } else {
386 1.59 gmcgarry sc->sc_bst = da->da_bst;
387 1.59 gmcgarry if (bus_space_map(sc->sc_bst, da->da_addr, da->da_size,
388 1.59 gmcgarry BUS_SPACE_MAP_LINEAR, &sc->sc_bsh)) {
389 1.79 tsutsui aprint_error(": can't map registers\n");
390 1.34 thorpej return;
391 1.34 thorpej }
392 1.79 tsutsui dcm = bus_space_vaddr(sc->sc_bst, sc->sc_bsh);
393 1.34 thorpej }
394 1.34 thorpej
395 1.34 thorpej sc->sc_dcm = dcm;
396 1.34 thorpej
397 1.38 scottr /*
398 1.38 scottr * XXX someone _should_ fix this; the self test screws
399 1.38 scottr * autoconfig messages.
400 1.38 scottr */
401 1.38 scottr if ((sc->sc_flags & DCM_ISCONSOLE) && dcmselftest(sc)) {
402 1.79 tsutsui aprint_normal("\n");
403 1.79 tsutsui aprint_error_dev(self, "self-test failed\n");
404 1.34 thorpej return;
405 1.24 thorpej }
406 1.20 thorpej
407 1.20 thorpej /* Extract configuration info from flags. */
408 1.70 thorpej sc->sc_softCAR = device_cfdata(self)->cf_flags & DCM_SOFTCAR;
409 1.70 thorpej sc->sc_flags |= device_cfdata(self)->cf_flags & DCM_FLAGMASK;
410 1.20 thorpej
411 1.20 thorpej /* Mark our unit as configured. */
412 1.20 thorpej sc->sc_flags |= DCM_ACTIVE;
413 1.20 thorpej
414 1.20 thorpej /* Establish the interrupt handler. */
415 1.79 tsutsui (void)dio_intr_establish(dcmintr, sc, da->da_ipl, IPL_TTY);
416 1.20 thorpej
417 1.1 cgd if (dcmistype == DIS_TIMER)
418 1.1 cgd dcmsetischeme(brd, DIS_RESET|DIS_TIMER);
419 1.1 cgd else
420 1.1 cgd dcmsetischeme(brd, DIS_RESET|DIS_PERCHAR);
421 1.1 cgd
422 1.1 cgd /* load pointers to modem control */
423 1.20 thorpej sc->sc_modem[0] = &dcm->dcm_modem0;
424 1.20 thorpej sc->sc_modem[1] = &dcm->dcm_modem1;
425 1.20 thorpej sc->sc_modem[2] = &dcm->dcm_modem2;
426 1.20 thorpej sc->sc_modem[3] = &dcm->dcm_modem3;
427 1.20 thorpej
428 1.1 cgd /* set DCD (modem) and CTS (flow control) on all ports */
429 1.20 thorpej if (sc->sc_flags & DCM_STDDCE)
430 1.1 cgd mbits = hp2dce_in(MI_CD|MI_CTS);
431 1.1 cgd else
432 1.1 cgd mbits = MI_CD|MI_CTS;
433 1.20 thorpej
434 1.20 thorpej for (i = 0; i < NDCMPORT; i++)
435 1.20 thorpej sc->sc_modem[i]->mdmmsk = mbits;
436 1.1 cgd
437 1.38 scottr /*
438 1.38 scottr * Get current state of mdmin register on all ports, so that
439 1.38 scottr * deltas will work properly.
440 1.38 scottr */
441 1.38 scottr for (i = 0; i < NDCMPORT; i++) {
442 1.38 scottr code = sc->sc_modem[i]->mdmin;
443 1.38 scottr if (sc->sc_flags & DCM_STDDCE)
444 1.38 scottr code = hp2dce_in(code);
445 1.38 scottr sc->sc_mcndlast[i] = code;
446 1.38 scottr }
447 1.38 scottr
448 1.1 cgd dcm->dcm_ic = IC_IE; /* turn all interrupts on */
449 1.20 thorpej
450 1.1 cgd /*
451 1.24 thorpej * Need to reset baud rate, etc. of next print so reset dcmconsinit.
452 1.1 cgd * Also make sure console is always "hardwired"
453 1.1 cgd */
454 1.24 thorpej if (sc->sc_flags & DCM_ISCONSOLE) {
455 1.1 cgd dcmconsinit = 0;
456 1.24 thorpej sc->sc_softCAR |= (1 << DCMCONSPORT);
457 1.79 tsutsui aprint_normal(": console on port %d\n", DCMCONSPORT);
458 1.20 thorpej } else
459 1.79 tsutsui aprint_normal("\n");
460 1.20 thorpej
461 1.20 thorpej #ifdef KGDB
462 1.52 gehenna if (cdevsw_lookup(kgdb_dev) == &dcm_cdevsw &&
463 1.20 thorpej DCMBOARD(DCMUNIT(kgdb_dev)) == brd) {
464 1.24 thorpej if (dcmconsole == DCMUNIT(kgdb_dev)) /* XXX fixme */
465 1.20 thorpej kgdb_dev = NODEV; /* can't debug over console port */
466 1.20 thorpej #ifndef KGDB_CHEAT
467 1.20 thorpej /*
468 1.20 thorpej * The following could potentially be replaced
469 1.20 thorpej * by the corresponding code in dcmcnprobe.
470 1.20 thorpej */
471 1.20 thorpej else {
472 1.22 thorpej dcminit(dcm, DCMPORT(DCMUNIT(kgdb_dev)),
473 1.22 thorpej kgdb_rate);
474 1.20 thorpej if (kgdb_debug_init) {
475 1.79 tsutsui aprint_normal_dev(self, "port %d: ",
476 1.20 thorpej DCMPORT(DCMUNIT(kgdb_dev)));
477 1.20 thorpej kgdb_connect(1);
478 1.20 thorpej } else
479 1.79 tsutsui aprint_normal_dev(self,
480 1.79 tsutsui "port %d: kgdb enabled\n",
481 1.20 thorpej DCMPORT(DCMUNIT(kgdb_dev)));
482 1.20 thorpej }
483 1.20 thorpej /* end could be replaced */
484 1.34 thorpej #endif /* KGDB_CHEAT */
485 1.1 cgd }
486 1.34 thorpej #endif /* KGDB */
487 1.1 cgd }
488 1.1 cgd
489 1.1 cgd /* ARGSUSED */
490 1.65 thorpej static int
491 1.68 christos dcmopen(dev_t dev, int flag, int mode, struct lwp *l)
492 1.1 cgd {
493 1.20 thorpej struct dcm_softc *sc;
494 1.20 thorpej struct tty *tp;
495 1.20 thorpej int unit, brd, port;
496 1.18 thorpej int error = 0, mbits, s;
497 1.1 cgd
498 1.20 thorpej unit = DCMUNIT(dev);
499 1.20 thorpej brd = DCMBOARD(unit);
500 1.20 thorpej port = DCMPORT(unit);
501 1.20 thorpej
502 1.81 cegger sc = device_lookup_private(&dcm_cd, brd);
503 1.81 cegger if (sc == NULL)
504 1.72 tsutsui return ENXIO;
505 1.20 thorpej
506 1.20 thorpej if ((sc->sc_flags & DCM_ACTIVE) == 0)
507 1.72 tsutsui return ENXIO;
508 1.20 thorpej
509 1.28 thorpej if (sc->sc_tty[port] == NULL) {
510 1.83 rmind tp = sc->sc_tty[port] = tty_alloc();
511 1.28 thorpej tty_attach(tp);
512 1.28 thorpej } else
513 1.20 thorpej tp = sc->sc_tty[port];
514 1.20 thorpej
515 1.1 cgd tp->t_oproc = dcmstart;
516 1.1 cgd tp->t_param = dcmparam;
517 1.1 cgd tp->t_dev = dev;
518 1.18 thorpej
519 1.76 elad if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
520 1.75 elad return (EBUSY);
521 1.44 thorpej
522 1.44 thorpej s = spltty();
523 1.44 thorpej
524 1.44 thorpej if ((tp->t_state & TS_ISOPEN) == 0 && tp->t_wopen == 0) {
525 1.18 thorpej /*
526 1.18 thorpej * Sanity clause: reset the card on first open.
527 1.18 thorpej * The card might be left in an inconsistent state
528 1.18 thorpej * if the card memory is read inadvertently.
529 1.18 thorpej */
530 1.22 thorpej dcminit(sc->sc_dcm, port, dcmdefaultrate);
531 1.18 thorpej
532 1.1 cgd ttychars(tp);
533 1.18 thorpej tp->t_iflag = TTYDEF_IFLAG;
534 1.18 thorpej tp->t_oflag = TTYDEF_OFLAG;
535 1.18 thorpej tp->t_cflag = TTYDEF_CFLAG;
536 1.18 thorpej tp->t_lflag = TTYDEF_LFLAG;
537 1.18 thorpej tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
538 1.18 thorpej
539 1.1 cgd (void) dcmparam(tp, &tp->t_termios);
540 1.1 cgd ttsetwater(tp);
541 1.18 thorpej
542 1.44 thorpej /* Set modem control state. */
543 1.44 thorpej mbits = MO_ON;
544 1.44 thorpej if (sc->sc_flags & DCM_STDDCE)
545 1.44 thorpej mbits |= MO_SR; /* pin 23, could be used as RTS */
546 1.44 thorpej
547 1.44 thorpej (void) dcmmctl(dev, mbits, DMSET); /* enable port */
548 1.20 thorpej
549 1.44 thorpej /* Set soft-carrier if so configured. */
550 1.44 thorpej if ((sc->sc_softCAR & (1 << port)) ||
551 1.44 thorpej (dcmmctl(dev, MO_OFF, DMGET) & MI_CD))
552 1.44 thorpej tp->t_state |= TS_CARR_ON;
553 1.44 thorpej }
554 1.18 thorpej
555 1.44 thorpej splx(s);
556 1.18 thorpej
557 1.1 cgd #ifdef DEBUG
558 1.1 cgd if (dcmdebug & DDB_MODEM)
559 1.31 christos printf("%s: dcmopen port %d softcarr %c\n",
560 1.79 tsutsui device_xname(sc->sc_dev), port,
561 1.79 tsutsui (tp->t_state & TS_CARR_ON) ? '1' : '0');
562 1.1 cgd #endif
563 1.18 thorpej
564 1.44 thorpej error = ttyopen(tp, DCMDIALOUT(dev), (flag & O_NONBLOCK));
565 1.44 thorpej if (error)
566 1.44 thorpej goto bad;
567 1.1 cgd
568 1.1 cgd #ifdef DEBUG
569 1.1 cgd if (dcmdebug & DDB_OPENCLOSE)
570 1.31 christos printf("%s port %d: dcmopen: st %x fl %x\n",
571 1.79 tsutsui device_xname(sc->sc_dev), port, tp->t_state, tp->t_flags);
572 1.1 cgd #endif
573 1.45 eeh error = (*tp->t_linesw->l_open)(dev, tp);
574 1.18 thorpej
575 1.44 thorpej bad:
576 1.72 tsutsui return error;
577 1.1 cgd }
578 1.63 tsutsui
579 1.1 cgd /*ARGSUSED*/
580 1.65 thorpej static int
581 1.68 christos dcmclose(dev_t dev, int flag, int mode, struct lwp *l)
582 1.1 cgd {
583 1.20 thorpej int s, unit, board, port;
584 1.20 thorpej struct dcm_softc *sc;
585 1.20 thorpej struct tty *tp;
586 1.63 tsutsui
587 1.20 thorpej unit = DCMUNIT(dev);
588 1.20 thorpej board = DCMBOARD(unit);
589 1.20 thorpej port = DCMPORT(unit);
590 1.20 thorpej
591 1.81 cegger sc = device_lookup_private(&dcm_cd,board);
592 1.20 thorpej tp = sc->sc_tty[port];
593 1.20 thorpej
594 1.45 eeh (*tp->t_linesw->l_close)(tp, flag);
595 1.18 thorpej
596 1.18 thorpej s = spltty();
597 1.18 thorpej
598 1.44 thorpej if (tp->t_cflag & HUPCL || tp->t_wopen != 0 ||
599 1.18 thorpej (tp->t_state & TS_ISOPEN) == 0)
600 1.1 cgd (void) dcmmctl(dev, MO_OFF, DMSET);
601 1.1 cgd #ifdef DEBUG
602 1.1 cgd if (dcmdebug & DDB_OPENCLOSE)
603 1.31 christos printf("%s port %d: dcmclose: st %x fl %x\n",
604 1.79 tsutsui device_xname(sc->sc_dev), port, tp->t_state, tp->t_flags);
605 1.1 cgd #endif
606 1.18 thorpej splx(s);
607 1.1 cgd ttyclose(tp);
608 1.12 mycroft #if 0
609 1.28 thorpej tty_detach(tp);
610 1.83 rmind tty_free(tp);
611 1.20 thorpej sc->sc_tty[port] == NULL;
612 1.12 mycroft #endif
613 1.72 tsutsui return 0;
614 1.1 cgd }
615 1.63 tsutsui
616 1.65 thorpej static int
617 1.65 thorpej dcmread(dev_t dev, struct uio *uio, int flag)
618 1.1 cgd {
619 1.20 thorpej int unit, board, port;
620 1.20 thorpej struct dcm_softc *sc;
621 1.36 scottr struct tty *tp;
622 1.20 thorpej
623 1.20 thorpej unit = DCMUNIT(dev);
624 1.20 thorpej board = DCMBOARD(unit);
625 1.20 thorpej port = DCMPORT(unit);
626 1.20 thorpej
627 1.81 cegger sc = device_lookup_private(&dcm_cd,board);
628 1.20 thorpej tp = sc->sc_tty[port];
629 1.14 mycroft
630 1.72 tsutsui return (*tp->t_linesw->l_read)(tp, uio, flag);
631 1.1 cgd }
632 1.63 tsutsui
633 1.65 thorpej static int
634 1.65 thorpej dcmwrite(dev_t dev, struct uio *uio, int flag)
635 1.1 cgd {
636 1.20 thorpej int unit, board, port;
637 1.20 thorpej struct dcm_softc *sc;
638 1.36 scottr struct tty *tp;
639 1.20 thorpej
640 1.20 thorpej unit = DCMUNIT(dev);
641 1.20 thorpej board = DCMBOARD(unit);
642 1.20 thorpej port = DCMPORT(unit);
643 1.20 thorpej
644 1.81 cegger sc = device_lookup_private(&dcm_cd, board);
645 1.20 thorpej tp = sc->sc_tty[port];
646 1.14 mycroft
647 1.72 tsutsui return (*tp->t_linesw->l_write)(tp, uio, flag);
648 1.46 scw }
649 1.46 scw
650 1.65 thorpej static int
651 1.68 christos dcmpoll(dev_t dev, int events, struct lwp *l)
652 1.46 scw {
653 1.46 scw int unit, board, port;
654 1.46 scw struct dcm_softc *sc;
655 1.46 scw struct tty *tp;
656 1.46 scw
657 1.46 scw unit = DCMUNIT(dev);
658 1.46 scw board = DCMBOARD(unit);
659 1.46 scw port = DCMPORT(unit);
660 1.46 scw
661 1.81 cegger sc = device_lookup_private(&dcm_cd, board);
662 1.46 scw tp = sc->sc_tty[port];
663 1.63 tsutsui
664 1.72 tsutsui return (*tp->t_linesw->l_poll)(tp, events, l);
665 1.1 cgd }
666 1.17 mycroft
667 1.65 thorpej static struct tty *
668 1.65 thorpej dcmtty(dev_t dev)
669 1.17 mycroft {
670 1.20 thorpej int unit, board, port;
671 1.20 thorpej struct dcm_softc *sc;
672 1.17 mycroft
673 1.20 thorpej unit = DCMUNIT(dev);
674 1.20 thorpej board = DCMBOARD(unit);
675 1.20 thorpej port = DCMPORT(unit);
676 1.20 thorpej
677 1.81 cegger sc = device_lookup_private(&dcm_cd, board);
678 1.20 thorpej
679 1.72 tsutsui return sc->sc_tty[port];
680 1.17 mycroft }
681 1.63 tsutsui
682 1.65 thorpej static int
683 1.65 thorpej dcmintr(void *arg)
684 1.1 cgd {
685 1.23 thorpej struct dcm_softc *sc = arg;
686 1.20 thorpej struct dcmdevice *dcm = sc->sc_dcm;
687 1.20 thorpej struct dcmischeme *dis = &sc->sc_scheme;
688 1.79 tsutsui int brd = device_unit(sc->sc_dev);
689 1.20 thorpej int code, i;
690 1.1 cgd int pcnd[4], mcode, mcnd[4];
691 1.1 cgd
692 1.1 cgd /*
693 1.36 scottr * Do all guarded accesses right off to minimize
694 1.1 cgd * block out of hardware.
695 1.1 cgd */
696 1.1 cgd SEM_LOCK(dcm);
697 1.1 cgd if ((dcm->dcm_ic & IC_IR) == 0) {
698 1.1 cgd SEM_UNLOCK(dcm);
699 1.72 tsutsui return 0;
700 1.1 cgd }
701 1.1 cgd for (i = 0; i < 4; i++) {
702 1.1 cgd pcnd[i] = dcm->dcm_icrtab[i].dcm_data;
703 1.1 cgd dcm->dcm_icrtab[i].dcm_data = 0;
704 1.20 thorpej code = sc->sc_modem[i]->mdmin;
705 1.20 thorpej if (sc->sc_flags & DCM_STDDCE)
706 1.1 cgd code = hp2dce_in(code);
707 1.1 cgd mcnd[i] = code;
708 1.1 cgd }
709 1.1 cgd code = dcm->dcm_iir & IIR_MASK;
710 1.1 cgd dcm->dcm_iir = 0; /* XXX doc claims read clears interrupt?! */
711 1.1 cgd mcode = dcm->dcm_modemintr;
712 1.1 cgd dcm->dcm_modemintr = 0;
713 1.1 cgd SEM_UNLOCK(dcm);
714 1.1 cgd
715 1.1 cgd #ifdef DEBUG
716 1.1 cgd if (dcmdebug & DDB_INTR) {
717 1.31 christos printf("%s: dcmintr: iir %x pc %x/%x/%x/%x ",
718 1.79 tsutsui device_xname(sc->sc_dev), code, pcnd[0], pcnd[1],
719 1.79 tsutsui pcnd[2], pcnd[3]);
720 1.31 christos printf("miir %x mc %x/%x/%x/%x\n",
721 1.79 tsutsui mcode, mcnd[0], mcnd[1], mcnd[2], mcnd[3]);
722 1.1 cgd }
723 1.1 cgd #endif
724 1.1 cgd if (code & IIR_TIMEO)
725 1.20 thorpej dcmrint(sc);
726 1.1 cgd if (code & IIR_PORT0)
727 1.20 thorpej dcmpint(sc, 0, pcnd[0]);
728 1.1 cgd if (code & IIR_PORT1)
729 1.20 thorpej dcmpint(sc, 1, pcnd[1]);
730 1.1 cgd if (code & IIR_PORT2)
731 1.20 thorpej dcmpint(sc, 2, pcnd[2]);
732 1.1 cgd if (code & IIR_PORT3)
733 1.20 thorpej dcmpint(sc, 3, pcnd[3]);
734 1.1 cgd if (code & IIR_MODM) {
735 1.1 cgd if (mcode == 0 || mcode & 0x1) /* mcode==0 -> 98642 board */
736 1.20 thorpej dcmmint(sc, 0, mcnd[0]);
737 1.1 cgd if (mcode & 0x2)
738 1.20 thorpej dcmmint(sc, 1, mcnd[1]);
739 1.1 cgd if (mcode & 0x4)
740 1.20 thorpej dcmmint(sc, 2, mcnd[2]);
741 1.1 cgd if (mcode & 0x8)
742 1.20 thorpej dcmmint(sc, 3, mcnd[3]);
743 1.1 cgd }
744 1.1 cgd
745 1.1 cgd /*
746 1.1 cgd * Chalk up a receiver interrupt if the timer running or one of
747 1.1 cgd * the ports reports a special character interrupt.
748 1.1 cgd */
749 1.1 cgd if ((code & IIR_TIMEO) ||
750 1.1 cgd ((pcnd[0]|pcnd[1]|pcnd[2]|pcnd[3]) & IT_SPEC))
751 1.1 cgd dis->dis_intr++;
752 1.1 cgd /*
753 1.1 cgd * See if it is time to check/change the interrupt rate.
754 1.1 cgd */
755 1.1 cgd if (dcmistype < 0 &&
756 1.74 tsutsui (i = time_second - dis->dis_time) >= dcminterval) {
757 1.1 cgd /*
758 1.1 cgd * If currently per-character and averaged over 70 interrupts
759 1.1 cgd * per-second (66 is threshold of 600 baud) in last interval,
760 1.1 cgd * switch to timer mode.
761 1.1 cgd *
762 1.1 cgd * XXX decay counts ala load average to avoid spikes?
763 1.1 cgd */
764 1.1 cgd if (dis->dis_perchar && dis->dis_intr > 70 * i)
765 1.1 cgd dcmsetischeme(brd, DIS_TIMER);
766 1.1 cgd /*
767 1.1 cgd * If currently using timer and had more interrupts than
768 1.1 cgd * received characters in the last interval, switch back
769 1.1 cgd * to per-character. Note that after changing to per-char
770 1.1 cgd * we must process any characters already in the queue
771 1.1 cgd * since they may have arrived before the bitmap was setup.
772 1.1 cgd *
773 1.1 cgd * XXX decay counts?
774 1.1 cgd */
775 1.1 cgd else if (!dis->dis_perchar && dis->dis_intr > dis->dis_char) {
776 1.1 cgd dcmsetischeme(brd, DIS_PERCHAR);
777 1.20 thorpej dcmrint(sc);
778 1.1 cgd }
779 1.1 cgd dis->dis_intr = dis->dis_char = 0;
780 1.74 tsutsui dis->dis_time = time_second;
781 1.1 cgd }
782 1.72 tsutsui return 1;
783 1.1 cgd }
784 1.1 cgd
785 1.1 cgd /*
786 1.1 cgd * Port interrupt. Can be two things:
787 1.1 cgd * First, it might be a special character (exception interrupt);
788 1.1 cgd * Second, it may be a buffer empty (transmit interrupt);
789 1.1 cgd */
790 1.65 thorpej static void
791 1.65 thorpej dcmpint(struct dcm_softc *sc, int port, int code)
792 1.1 cgd {
793 1.1 cgd
794 1.1 cgd if (code & IT_SPEC)
795 1.20 thorpej dcmreadbuf(sc, port);
796 1.1 cgd if (code & IT_TX)
797 1.20 thorpej dcmxint(sc, port);
798 1.1 cgd }
799 1.1 cgd
800 1.65 thorpej static void
801 1.65 thorpej dcmrint(struct dcm_softc *sc)
802 1.1 cgd {
803 1.20 thorpej int port;
804 1.1 cgd
805 1.20 thorpej for (port = 0; port < NDCMPORT; port++)
806 1.20 thorpej dcmreadbuf(sc, port);
807 1.1 cgd }
808 1.1 cgd
809 1.65 thorpej static void
810 1.65 thorpej dcmreadbuf(struct dcm_softc *sc, int port)
811 1.1 cgd {
812 1.20 thorpej struct dcmdevice *dcm = sc->sc_dcm;
813 1.20 thorpej struct dcmpreg *pp = dcm_preg(dcm, port);
814 1.20 thorpej struct dcmrfifo *fifo;
815 1.38 scottr struct tty *tp;
816 1.20 thorpej int c, stat;
817 1.20 thorpej u_int head;
818 1.1 cgd int nch = 0;
819 1.14 mycroft #ifdef DCMSTATS
820 1.20 thorpej struct dcmstats *dsp = &sc->sc_stats;
821 1.1 cgd
822 1.1 cgd dsp->rints++;
823 1.1 cgd #endif
824 1.38 scottr tp = sc->sc_tty[port];
825 1.40 scottr if (tp == NULL)
826 1.38 scottr return;
827 1.38 scottr
828 1.1 cgd if ((tp->t_state & TS_ISOPEN) == 0) {
829 1.1 cgd #ifdef KGDB
830 1.52 gehenna int maj;
831 1.52 gehenna
832 1.52 gehenna maj = cdevsw_lookup_major(&dcm_cdevsw);
833 1.52 gehenna
834 1.52 gehenna if ((makedev(maj, minor(tp->t_dev)) == kgdb_dev) &&
835 1.1 cgd (head = pp->r_head & RX_MASK) != (pp->r_tail & RX_MASK) &&
836 1.14 mycroft dcm->dcm_rfifos[3-port][head>>1].data_char == FRAME_START) {
837 1.1 cgd pp->r_head = (head + 2) & RX_MASK;
838 1.1 cgd kgdb_connect(0); /* trap into kgdb */
839 1.1 cgd return;
840 1.1 cgd }
841 1.1 cgd #endif /* KGDB */
842 1.1 cgd pp->r_head = pp->r_tail & RX_MASK;
843 1.1 cgd return;
844 1.1 cgd }
845 1.1 cgd
846 1.1 cgd head = pp->r_head & RX_MASK;
847 1.1 cgd fifo = &dcm->dcm_rfifos[3-port][head>>1];
848 1.1 cgd /*
849 1.1 cgd * XXX upper bound on how many chars we will take in one swallow?
850 1.1 cgd */
851 1.1 cgd while (head != (pp->r_tail & RX_MASK)) {
852 1.1 cgd /*
853 1.1 cgd * Get character/status and update head pointer as fast
854 1.1 cgd * as possible to make room for more characters.
855 1.1 cgd */
856 1.1 cgd c = fifo->data_char;
857 1.1 cgd stat = fifo->data_stat;
858 1.1 cgd head = (head + 2) & RX_MASK;
859 1.1 cgd pp->r_head = head;
860 1.1 cgd fifo = head ? fifo+1 : &dcm->dcm_rfifos[3-port][0];
861 1.1 cgd nch++;
862 1.1 cgd
863 1.1 cgd #ifdef DEBUG
864 1.1 cgd if (dcmdebug & DDB_INPUT)
865 1.79 tsutsui printf("%s port %d: "
866 1.79 tsutsui "dcmreadbuf: c%x('%c') s%x f%x h%x t%x\n",
867 1.79 tsutsui device_xname(sc->sc_dev), port,
868 1.79 tsutsui c&0xFF, c, stat&0xFF,
869 1.79 tsutsui tp->t_flags, head, pp->r_tail);
870 1.1 cgd #endif
871 1.1 cgd /*
872 1.1 cgd * Check for and handle errors
873 1.1 cgd */
874 1.1 cgd if (stat & RD_MASK) {
875 1.1 cgd #ifdef DEBUG
876 1.1 cgd if (dcmdebug & (DDB_INPUT|DDB_SIOERR))
877 1.79 tsutsui printf("%s port %d: "
878 1.79 tsutsui "dcmreadbuf: err: c%x('%c') s%x\n",
879 1.79 tsutsui device_xname(sc->sc_dev), port,
880 1.79 tsutsui stat, c&0xFF, c);
881 1.1 cgd #endif
882 1.1 cgd if (stat & (RD_BD | RD_FE))
883 1.1 cgd c |= TTY_FE;
884 1.1 cgd else if (stat & RD_PE)
885 1.1 cgd c |= TTY_PE;
886 1.1 cgd else if (stat & RD_OVF)
887 1.1 cgd log(LOG_WARNING,
888 1.20 thorpej "%s port %d: silo overflow\n",
889 1.79 tsutsui device_xname(sc->sc_dev), port);
890 1.1 cgd else if (stat & RD_OE)
891 1.1 cgd log(LOG_WARNING,
892 1.20 thorpej "%s port %d: uart overflow\n",
893 1.79 tsutsui device_xname(sc->sc_dev), port);
894 1.1 cgd }
895 1.45 eeh (*tp->t_linesw->l_rint)(c, tp);
896 1.1 cgd }
897 1.20 thorpej sc->sc_scheme.dis_char += nch;
898 1.20 thorpej
899 1.14 mycroft #ifdef DCMSTATS
900 1.1 cgd dsp->rchars += nch;
901 1.1 cgd if (nch <= DCMRBSIZE)
902 1.1 cgd dsp->rsilo[nch]++;
903 1.1 cgd else
904 1.1 cgd dsp->rsilo[DCMRBSIZE+1]++;
905 1.1 cgd #endif
906 1.1 cgd }
907 1.1 cgd
908 1.65 thorpej static void
909 1.65 thorpej dcmxint(struct dcm_softc *sc, int port)
910 1.1 cgd {
911 1.38 scottr struct tty *tp;
912 1.38 scottr
913 1.38 scottr tp = sc->sc_tty[port];
914 1.38 scottr if (tp == NULL || (tp->t_state & TS_ISOPEN) == 0)
915 1.38 scottr return;
916 1.20 thorpej
917 1.1 cgd tp->t_state &= ~TS_BUSY;
918 1.1 cgd if (tp->t_state & TS_FLUSH)
919 1.1 cgd tp->t_state &= ~TS_FLUSH;
920 1.45 eeh (*tp->t_linesw->l_start)(tp);
921 1.1 cgd }
922 1.1 cgd
923 1.65 thorpej static void
924 1.65 thorpej dcmmint(struct dcm_softc *sc, int port, int mcnd)
925 1.1 cgd {
926 1.1 cgd int delta;
927 1.20 thorpej struct tty *tp;
928 1.20 thorpej struct dcmdevice *dcm = sc->sc_dcm;
929 1.20 thorpej
930 1.1 cgd #ifdef DEBUG
931 1.1 cgd if (dcmdebug & DDB_MODEM)
932 1.31 christos printf("%s port %d: dcmmint: mcnd %x mcndlast %x\n",
933 1.79 tsutsui device_xname(sc->sc_dev), port, mcnd,
934 1.79 tsutsui sc->sc_mcndlast[port]);
935 1.1 cgd #endif
936 1.20 thorpej delta = mcnd ^ sc->sc_mcndlast[port];
937 1.20 thorpej sc->sc_mcndlast[port] = mcnd;
938 1.58 gmcgarry tp = sc->sc_tty[port];
939 1.58 gmcgarry if (tp == NULL || (tp->t_state & TS_ISOPEN) == 0)
940 1.58 gmcgarry return;
941 1.58 gmcgarry
942 1.1 cgd if ((delta & MI_CTS) && (tp->t_state & TS_ISOPEN) &&
943 1.55 gmcgarry (tp->t_cflag & CCTS_OFLOW)) {
944 1.1 cgd if (mcnd & MI_CTS) {
945 1.1 cgd tp->t_state &= ~TS_TTSTOP;
946 1.1 cgd ttstart(tp);
947 1.1 cgd } else
948 1.1 cgd tp->t_state |= TS_TTSTOP; /* inline dcmstop */
949 1.1 cgd }
950 1.1 cgd if (delta & MI_CD) {
951 1.1 cgd if (mcnd & MI_CD)
952 1.45 eeh (void)(*tp->t_linesw->l_modem)(tp, 1);
953 1.20 thorpej else if ((sc->sc_softCAR & (1 << port)) == 0 &&
954 1.45 eeh (*tp->t_linesw->l_modem)(tp, 0) == 0) {
955 1.20 thorpej sc->sc_modem[port]->mdmout = MO_OFF;
956 1.1 cgd SEM_LOCK(dcm);
957 1.20 thorpej dcm->dcm_modemchng |= (1 << port);
958 1.1 cgd dcm->dcm_cr |= CR_MODM;
959 1.1 cgd SEM_UNLOCK(dcm);
960 1.1 cgd DELAY(10); /* time to change lines */
961 1.1 cgd }
962 1.1 cgd }
963 1.1 cgd }
964 1.1 cgd
965 1.65 thorpej static int
966 1.77 christos dcmioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
967 1.1 cgd {
968 1.20 thorpej struct dcm_softc *sc;
969 1.20 thorpej struct tty *tp;
970 1.20 thorpej struct dcmdevice *dcm;
971 1.20 thorpej int board, port, unit = DCMUNIT(dev);
972 1.1 cgd int error, s;
973 1.20 thorpej
974 1.20 thorpej port = DCMPORT(unit);
975 1.20 thorpej board = DCMBOARD(unit);
976 1.20 thorpej
977 1.81 cegger sc = device_lookup_private(&dcm_cd, board);
978 1.20 thorpej dcm = sc->sc_dcm;
979 1.20 thorpej tp = sc->sc_tty[port];
980 1.63 tsutsui
981 1.1 cgd #ifdef DEBUG
982 1.1 cgd if (dcmdebug & DDB_IOCTL)
983 1.37 scottr printf("%s port %d: dcmioctl: cmd %lx data %x flag %x\n",
984 1.79 tsutsui device_xname(sc->sc_dev), port, cmd, *(int *)data, flag);
985 1.1 cgd #endif
986 1.51 atatat
987 1.68 christos error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
988 1.51 atatat if (error != EPASSTHROUGH)
989 1.72 tsutsui return error;
990 1.51 atatat
991 1.68 christos error = ttioctl(tp, cmd, data, flag, l);
992 1.51 atatat if (error != EPASSTHROUGH)
993 1.72 tsutsui return error;
994 1.1 cgd
995 1.1 cgd switch (cmd) {
996 1.1 cgd case TIOCSBRK:
997 1.1 cgd /*
998 1.1 cgd * Wait for transmitter buffer to empty
999 1.1 cgd */
1000 1.1 cgd s = spltty();
1001 1.1 cgd while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)
1002 1.1 cgd DELAY(DCM_USPERCH(tp->t_ospeed));
1003 1.1 cgd SEM_LOCK(dcm);
1004 1.1 cgd dcm->dcm_cmdtab[port].dcm_data |= CT_BRK;
1005 1.1 cgd dcm->dcm_cr |= (1 << port); /* start break */
1006 1.1 cgd SEM_UNLOCK(dcm);
1007 1.1 cgd splx(s);
1008 1.1 cgd break;
1009 1.1 cgd
1010 1.1 cgd case TIOCCBRK:
1011 1.1 cgd SEM_LOCK(dcm);
1012 1.1 cgd dcm->dcm_cmdtab[port].dcm_data |= CT_BRK;
1013 1.1 cgd dcm->dcm_cr |= (1 << port); /* end break */
1014 1.1 cgd SEM_UNLOCK(dcm);
1015 1.1 cgd break;
1016 1.1 cgd
1017 1.1 cgd case TIOCSDTR:
1018 1.1 cgd (void) dcmmctl(dev, MO_ON, DMBIS);
1019 1.1 cgd break;
1020 1.1 cgd
1021 1.1 cgd case TIOCCDTR:
1022 1.1 cgd (void) dcmmctl(dev, MO_ON, DMBIC);
1023 1.1 cgd break;
1024 1.1 cgd
1025 1.1 cgd case TIOCMSET:
1026 1.1 cgd (void) dcmmctl(dev, *(int *)data, DMSET);
1027 1.1 cgd break;
1028 1.1 cgd
1029 1.1 cgd case TIOCMBIS:
1030 1.1 cgd (void) dcmmctl(dev, *(int *)data, DMBIS);
1031 1.1 cgd break;
1032 1.1 cgd
1033 1.1 cgd case TIOCMBIC:
1034 1.1 cgd (void) dcmmctl(dev, *(int *)data, DMBIC);
1035 1.1 cgd break;
1036 1.1 cgd
1037 1.1 cgd case TIOCMGET:
1038 1.1 cgd *(int *)data = dcmmctl(dev, 0, DMGET);
1039 1.1 cgd break;
1040 1.18 thorpej
1041 1.18 thorpej case TIOCGFLAGS: {
1042 1.18 thorpej int bits = 0;
1043 1.18 thorpej
1044 1.20 thorpej if ((sc->sc_softCAR & (1 << port)))
1045 1.18 thorpej bits |= TIOCFLAG_SOFTCAR;
1046 1.18 thorpej
1047 1.18 thorpej if (tp->t_cflag & CLOCAL)
1048 1.18 thorpej bits |= TIOCFLAG_CLOCAL;
1049 1.18 thorpej
1050 1.18 thorpej *(int *)data = bits;
1051 1.18 thorpej break;
1052 1.18 thorpej }
1053 1.18 thorpej
1054 1.18 thorpej case TIOCSFLAGS: {
1055 1.18 thorpej int userbits;
1056 1.18 thorpej
1057 1.75 elad if (kauth_authorize_device_tty(l->l_cred,
1058 1.75 elad KAUTH_DEVICE_TTY_PRIVSET, tp))
1059 1.75 elad return (EPERM);
1060 1.18 thorpej
1061 1.18 thorpej userbits = *(int *)data;
1062 1.18 thorpej
1063 1.18 thorpej if ((userbits & TIOCFLAG_SOFTCAR) ||
1064 1.24 thorpej ((sc->sc_flags & DCM_ISCONSOLE) &&
1065 1.24 thorpej (port == DCMCONSPORT)))
1066 1.20 thorpej sc->sc_softCAR |= (1 << port);
1067 1.18 thorpej
1068 1.18 thorpej if (userbits & TIOCFLAG_CLOCAL)
1069 1.18 thorpej tp->t_cflag |= CLOCAL;
1070 1.18 thorpej
1071 1.18 thorpej break;
1072 1.18 thorpej }
1073 1.1 cgd
1074 1.1 cgd default:
1075 1.72 tsutsui return EPASSTHROUGH;
1076 1.1 cgd }
1077 1.72 tsutsui return 0;
1078 1.1 cgd }
1079 1.1 cgd
1080 1.65 thorpej static int
1081 1.65 thorpej dcmparam(struct tty *tp, struct termios *t)
1082 1.1 cgd {
1083 1.20 thorpej struct dcm_softc *sc;
1084 1.20 thorpej struct dcmdevice *dcm;
1085 1.20 thorpej int unit, board, port, mode, cflag = t->c_cflag;
1086 1.1 cgd int ospeed = ttspeedtab(t->c_ospeed, dcmspeedtab);
1087 1.1 cgd
1088 1.20 thorpej unit = DCMUNIT(tp->t_dev);
1089 1.20 thorpej board = DCMBOARD(unit);
1090 1.20 thorpej port = DCMPORT(unit);
1091 1.20 thorpej
1092 1.81 cegger sc = device_lookup_private(&dcm_cd, board);
1093 1.20 thorpej dcm = sc->sc_dcm;
1094 1.20 thorpej
1095 1.1 cgd /* check requested parameters */
1096 1.59 gmcgarry if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
1097 1.72 tsutsui return EINVAL;
1098 1.59 gmcgarry /* and copy to tty */
1099 1.59 gmcgarry tp->t_ispeed = t->c_ispeed;
1100 1.59 gmcgarry tp->t_ospeed = t->c_ospeed;
1101 1.59 gmcgarry tp->t_cflag = cflag;
1102 1.1 cgd if (ospeed == 0) {
1103 1.72 tsutsui (void)dcmmctl(DCMUNIT(tp->t_dev), MO_OFF, DMSET);
1104 1.72 tsutsui return 0;
1105 1.1 cgd }
1106 1.1 cgd
1107 1.1 cgd mode = 0;
1108 1.1 cgd switch (cflag&CSIZE) {
1109 1.1 cgd case CS5:
1110 1.1 cgd mode = LC_5BITS; break;
1111 1.1 cgd case CS6:
1112 1.1 cgd mode = LC_6BITS; break;
1113 1.1 cgd case CS7:
1114 1.1 cgd mode = LC_7BITS; break;
1115 1.1 cgd case CS8:
1116 1.1 cgd mode = LC_8BITS; break;
1117 1.1 cgd }
1118 1.1 cgd if (cflag&PARENB) {
1119 1.1 cgd if (cflag&PARODD)
1120 1.1 cgd mode |= LC_PODD;
1121 1.1 cgd else
1122 1.1 cgd mode |= LC_PEVEN;
1123 1.1 cgd }
1124 1.1 cgd if (cflag&CSTOPB)
1125 1.1 cgd mode |= LC_2STOP;
1126 1.1 cgd else
1127 1.1 cgd mode |= LC_1STOP;
1128 1.1 cgd #ifdef DEBUG
1129 1.1 cgd if (dcmdebug & DDB_PARAM)
1130 1.79 tsutsui printf("%s port %d: "
1131 1.79 tsutsui "dcmparam: cflag %x mode %x speed %d uperch %d\n",
1132 1.79 tsutsui device_xname(sc->sc_dev), port, cflag, mode, tp->t_ospeed,
1133 1.79 tsutsui DCM_USPERCH(tp->t_ospeed));
1134 1.1 cgd #endif
1135 1.1 cgd
1136 1.1 cgd /*
1137 1.1 cgd * Wait for transmitter buffer to empty.
1138 1.1 cgd */
1139 1.1 cgd while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)
1140 1.1 cgd DELAY(DCM_USPERCH(tp->t_ospeed));
1141 1.1 cgd /*
1142 1.1 cgd * Make changes known to hardware.
1143 1.1 cgd */
1144 1.1 cgd dcm->dcm_data[port].dcm_baud = ospeed;
1145 1.1 cgd dcm->dcm_data[port].dcm_conf = mode;
1146 1.1 cgd SEM_LOCK(dcm);
1147 1.1 cgd dcm->dcm_cmdtab[port].dcm_data |= CT_CON;
1148 1.1 cgd dcm->dcm_cr |= (1 << port);
1149 1.1 cgd SEM_UNLOCK(dcm);
1150 1.1 cgd /*
1151 1.1 cgd * Delay for config change to take place. Weighted by baud.
1152 1.1 cgd * XXX why do we do this?
1153 1.1 cgd */
1154 1.1 cgd DELAY(16 * DCM_USPERCH(tp->t_ospeed));
1155 1.72 tsutsui return 0;
1156 1.1 cgd }
1157 1.63 tsutsui
1158 1.65 thorpej static void
1159 1.65 thorpej dcmstart(struct tty *tp)
1160 1.1 cgd {
1161 1.20 thorpej struct dcm_softc *sc;
1162 1.20 thorpej struct dcmdevice *dcm;
1163 1.20 thorpej struct dcmpreg *pp;
1164 1.20 thorpej struct dcmtfifo *fifo;
1165 1.20 thorpej char *bp;
1166 1.20 thorpej u_int head, tail, next;
1167 1.20 thorpej int unit, board, port, nch;
1168 1.1 cgd char buf[16];
1169 1.1 cgd int s;
1170 1.14 mycroft #ifdef DCMSTATS
1171 1.20 thorpej struct dcmstats *dsp = &sc->sc_stats;
1172 1.1 cgd int tch = 0;
1173 1.1 cgd #endif
1174 1.1 cgd
1175 1.20 thorpej unit = DCMUNIT(tp->t_dev);
1176 1.20 thorpej board = DCMBOARD(unit);
1177 1.20 thorpej port = DCMPORT(unit);
1178 1.20 thorpej
1179 1.81 cegger sc = device_lookup_private(&dcm_cd, board);
1180 1.20 thorpej dcm = sc->sc_dcm;
1181 1.20 thorpej
1182 1.1 cgd s = spltty();
1183 1.14 mycroft #ifdef DCMSTATS
1184 1.1 cgd dsp->xints++;
1185 1.1 cgd #endif
1186 1.1 cgd #ifdef DEBUG
1187 1.1 cgd if (dcmdebug & DDB_OUTPUT)
1188 1.31 christos printf("%s port %d: dcmstart: state %x flags %x outcc %d\n",
1189 1.79 tsutsui device_xname(sc->sc_dev), port, tp->t_state, tp->t_flags,
1190 1.79 tsutsui tp->t_outq.c_cc);
1191 1.1 cgd #endif
1192 1.1 cgd if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
1193 1.1 cgd goto out;
1194 1.78 ad if (!ttypull(tp)) {
1195 1.14 mycroft #ifdef DCMSTATS
1196 1.1 cgd dsp->xempty++;
1197 1.1 cgd #endif
1198 1.1 cgd goto out;
1199 1.1 cgd }
1200 1.1 cgd
1201 1.1 cgd pp = dcm_preg(dcm, port);
1202 1.1 cgd tail = pp->t_tail & TX_MASK;
1203 1.1 cgd next = (tail + 1) & TX_MASK;
1204 1.1 cgd head = pp->t_head & TX_MASK;
1205 1.1 cgd if (head == next)
1206 1.1 cgd goto out;
1207 1.1 cgd fifo = &dcm->dcm_tfifos[3-port][tail];
1208 1.1 cgd again:
1209 1.1 cgd nch = q_to_b(&tp->t_outq, buf, (head - next) & TX_MASK);
1210 1.14 mycroft #ifdef DCMSTATS
1211 1.1 cgd tch += nch;
1212 1.1 cgd #endif
1213 1.1 cgd #ifdef DEBUG
1214 1.1 cgd if (dcmdebug & DDB_OUTPUT)
1215 1.31 christos printf("\thead %x tail %x nch %d\n", head, tail, nch);
1216 1.1 cgd #endif
1217 1.1 cgd /*
1218 1.1 cgd * Loop transmitting all the characters we can.
1219 1.1 cgd */
1220 1.1 cgd for (bp = buf; --nch >= 0; bp++) {
1221 1.1 cgd fifo->data_char = *bp;
1222 1.1 cgd pp->t_tail = next;
1223 1.1 cgd /*
1224 1.1 cgd * If this is the first character,
1225 1.1 cgd * get the hardware moving right now.
1226 1.1 cgd */
1227 1.1 cgd if (bp == buf) {
1228 1.1 cgd tp->t_state |= TS_BUSY;
1229 1.1 cgd SEM_LOCK(dcm);
1230 1.1 cgd dcm->dcm_cmdtab[port].dcm_data |= CT_TX;
1231 1.1 cgd dcm->dcm_cr |= (1 << port);
1232 1.1 cgd SEM_UNLOCK(dcm);
1233 1.1 cgd }
1234 1.1 cgd tail = next;
1235 1.1 cgd fifo = tail ? fifo+1 : &dcm->dcm_tfifos[3-port][0];
1236 1.1 cgd next = (next + 1) & TX_MASK;
1237 1.1 cgd }
1238 1.1 cgd /*
1239 1.1 cgd * Head changed while we were loading the buffer,
1240 1.1 cgd * go back and load some more if we can.
1241 1.1 cgd */
1242 1.7 mycroft if (tp->t_outq.c_cc && head != (pp->t_head & TX_MASK)) {
1243 1.14 mycroft #ifdef DCMSTATS
1244 1.1 cgd dsp->xrestarts++;
1245 1.1 cgd #endif
1246 1.1 cgd head = pp->t_head & TX_MASK;
1247 1.1 cgd goto again;
1248 1.1 cgd }
1249 1.1 cgd
1250 1.1 cgd /*
1251 1.1 cgd * Kick it one last time in case it finished while we were
1252 1.1 cgd * loading the last bunch.
1253 1.1 cgd */
1254 1.1 cgd if (bp > &buf[1]) {
1255 1.1 cgd tp->t_state |= TS_BUSY;
1256 1.1 cgd SEM_LOCK(dcm);
1257 1.1 cgd dcm->dcm_cmdtab[port].dcm_data |= CT_TX;
1258 1.1 cgd dcm->dcm_cr |= (1 << port);
1259 1.1 cgd SEM_UNLOCK(dcm);
1260 1.1 cgd }
1261 1.1 cgd #ifdef DEBUG
1262 1.1 cgd if (dcmdebug & DDB_INTR)
1263 1.37 scottr printf("%s port %d: dcmstart: head %x tail %x outqcc %d\n",
1264 1.79 tsutsui device_xname(sc->sc_dev), port, head, tail,
1265 1.79 tsutsui tp->t_outq.c_cc);
1266 1.1 cgd #endif
1267 1.1 cgd out:
1268 1.14 mycroft #ifdef DCMSTATS
1269 1.1 cgd dsp->xchars += tch;
1270 1.1 cgd if (tch <= DCMXBSIZE)
1271 1.1 cgd dsp->xsilo[tch]++;
1272 1.1 cgd else
1273 1.1 cgd dsp->xsilo[DCMXBSIZE+1]++;
1274 1.1 cgd #endif
1275 1.1 cgd splx(s);
1276 1.1 cgd }
1277 1.63 tsutsui
1278 1.1 cgd /*
1279 1.1 cgd * Stop output on a line.
1280 1.1 cgd */
1281 1.65 thorpej static void
1282 1.65 thorpej dcmstop(struct tty *tp, int flag)
1283 1.1 cgd {
1284 1.1 cgd int s;
1285 1.1 cgd
1286 1.1 cgd s = spltty();
1287 1.1 cgd if (tp->t_state & TS_BUSY) {
1288 1.1 cgd /* XXX is there some way to safely stop transmission? */
1289 1.1 cgd if ((tp->t_state&TS_TTSTOP) == 0)
1290 1.1 cgd tp->t_state |= TS_FLUSH;
1291 1.1 cgd }
1292 1.1 cgd splx(s);
1293 1.1 cgd }
1294 1.63 tsutsui
1295 1.1 cgd /*
1296 1.1 cgd * Modem control
1297 1.1 cgd */
1298 1.36 scottr int
1299 1.65 thorpej dcmmctl(dev_t dev, int bits, int how)
1300 1.1 cgd {
1301 1.20 thorpej struct dcm_softc *sc;
1302 1.20 thorpej struct dcmdevice *dcm;
1303 1.20 thorpej int s, unit, brd, port, hit = 0;
1304 1.20 thorpej
1305 1.20 thorpej unit = DCMUNIT(dev);
1306 1.20 thorpej brd = DCMBOARD(unit);
1307 1.20 thorpej port = DCMPORT(unit);
1308 1.34 thorpej
1309 1.81 cegger sc = device_lookup_private(&dcm_cd, brd);
1310 1.20 thorpej dcm = sc->sc_dcm;
1311 1.1 cgd
1312 1.1 cgd #ifdef DEBUG
1313 1.1 cgd if (dcmdebug & DDB_MODEM)
1314 1.31 christos printf("%s port %d: dcmmctl: bits 0x%x how %x\n",
1315 1.79 tsutsui device_xname(sc->sc_dev), port, bits, how);
1316 1.1 cgd #endif
1317 1.1 cgd
1318 1.1 cgd s = spltty();
1319 1.20 thorpej
1320 1.1 cgd switch (how) {
1321 1.1 cgd case DMSET:
1322 1.20 thorpej sc->sc_modem[port]->mdmout = bits;
1323 1.1 cgd hit++;
1324 1.1 cgd break;
1325 1.1 cgd
1326 1.1 cgd case DMBIS:
1327 1.20 thorpej sc->sc_modem[port]->mdmout |= bits;
1328 1.1 cgd hit++;
1329 1.1 cgd break;
1330 1.1 cgd
1331 1.1 cgd case DMBIC:
1332 1.20 thorpej sc->sc_modem[port]->mdmout &= ~bits;
1333 1.1 cgd hit++;
1334 1.1 cgd break;
1335 1.1 cgd
1336 1.1 cgd case DMGET:
1337 1.20 thorpej bits = sc->sc_modem[port]->mdmin;
1338 1.20 thorpej if (sc->sc_flags & DCM_STDDCE)
1339 1.1 cgd bits = hp2dce_in(bits);
1340 1.1 cgd break;
1341 1.1 cgd }
1342 1.1 cgd if (hit) {
1343 1.1 cgd SEM_LOCK(dcm);
1344 1.1 cgd dcm->dcm_modemchng |= 1<<(unit & 3);
1345 1.1 cgd dcm->dcm_cr |= CR_MODM;
1346 1.1 cgd SEM_UNLOCK(dcm);
1347 1.1 cgd DELAY(10); /* delay until done */
1348 1.49 gmcgarry splx(s);
1349 1.1 cgd }
1350 1.72 tsutsui return bits;
1351 1.1 cgd }
1352 1.1 cgd
1353 1.1 cgd /*
1354 1.1 cgd * Set board to either interrupt per-character or at a fixed interval.
1355 1.1 cgd */
1356 1.65 thorpej static void
1357 1.65 thorpej dcmsetischeme(int brd, int flags)
1358 1.1 cgd {
1359 1.81 cegger struct dcm_softc *sc = device_lookup_private(&dcm_cd, brd);
1360 1.20 thorpej struct dcmdevice *dcm = sc->sc_dcm;
1361 1.20 thorpej struct dcmischeme *dis = &sc->sc_scheme;
1362 1.20 thorpej int i;
1363 1.1 cgd u_char mask;
1364 1.1 cgd int perchar = flags & DIS_PERCHAR;
1365 1.1 cgd
1366 1.1 cgd #ifdef DEBUG
1367 1.1 cgd if (dcmdebug & DDB_INTSCHM)
1368 1.31 christos printf("%s: dcmsetischeme(%d): cur %d, ints %d, chars %d\n",
1369 1.79 tsutsui device_xname(sc->sc_dev), perchar, dis->dis_perchar,
1370 1.79 tsutsui dis->dis_intr, dis->dis_char);
1371 1.1 cgd if ((flags & DIS_RESET) == 0 && perchar == dis->dis_perchar) {
1372 1.31 christos printf("%s: dcmsetischeme: redundent request %d\n",
1373 1.79 tsutsui device_xname(sc->sc_dev), perchar);
1374 1.1 cgd return;
1375 1.1 cgd }
1376 1.1 cgd #endif
1377 1.1 cgd /*
1378 1.1 cgd * If perchar is non-zero, we enable interrupts on all characters
1379 1.1 cgd * otherwise we disable perchar interrupts and use periodic
1380 1.1 cgd * polling interrupts.
1381 1.1 cgd */
1382 1.1 cgd dis->dis_perchar = perchar;
1383 1.1 cgd mask = perchar ? 0xf : 0x0;
1384 1.1 cgd for (i = 0; i < 256; i++)
1385 1.1 cgd dcm->dcm_bmap[i].data_data = mask;
1386 1.1 cgd /*
1387 1.1 cgd * Don't slow down tandem mode, interrupt on flow control
1388 1.1 cgd * chars for any port on the board.
1389 1.1 cgd */
1390 1.1 cgd if (!perchar) {
1391 1.36 scottr struct tty *tp;
1392 1.1 cgd int c;
1393 1.1 cgd
1394 1.20 thorpej for (i = 0; i < NDCMPORT; i++) {
1395 1.20 thorpej tp = sc->sc_tty[i];
1396 1.20 thorpej
1397 1.86 dholland c = tty_getctrlchar(tp, VSTART);
1398 1.86 dholland if (c != _POSIX_VDISABLE)
1399 1.1 cgd dcm->dcm_bmap[c].data_data |= (1 << i);
1400 1.86 dholland c = tty_getctrlchar(tp, VSTOP);
1401 1.86 dholland if (c != _POSIX_VDISABLE)
1402 1.1 cgd dcm->dcm_bmap[c].data_data |= (1 << i);
1403 1.1 cgd }
1404 1.1 cgd }
1405 1.1 cgd /*
1406 1.1 cgd * Board starts with timer disabled so if first call is to
1407 1.1 cgd * set perchar mode then we don't want to toggle the timer.
1408 1.1 cgd */
1409 1.1 cgd if (flags == (DIS_RESET|DIS_PERCHAR))
1410 1.1 cgd return;
1411 1.1 cgd /*
1412 1.1 cgd * Toggle card 16.7ms interrupts (we first make sure that card
1413 1.1 cgd * has cleared the bit so it will see the toggle).
1414 1.1 cgd */
1415 1.1 cgd while (dcm->dcm_cr & CR_TIMER)
1416 1.1 cgd ;
1417 1.1 cgd SEM_LOCK(dcm);
1418 1.1 cgd dcm->dcm_cr |= CR_TIMER;
1419 1.1 cgd SEM_UNLOCK(dcm);
1420 1.1 cgd }
1421 1.1 cgd
1422 1.65 thorpej static void
1423 1.65 thorpej dcminit(struct dcmdevice *dcm, int port, int rate)
1424 1.22 thorpej {
1425 1.22 thorpej int s, mode;
1426 1.22 thorpej
1427 1.22 thorpej mode = LC_8BITS | LC_1STOP;
1428 1.22 thorpej
1429 1.22 thorpej s = splhigh();
1430 1.22 thorpej
1431 1.22 thorpej /*
1432 1.22 thorpej * Wait for transmitter buffer to empty.
1433 1.22 thorpej */
1434 1.22 thorpej while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)
1435 1.22 thorpej DELAY(DCM_USPERCH(rate));
1436 1.22 thorpej
1437 1.22 thorpej /*
1438 1.22 thorpej * Make changes known to hardware.
1439 1.22 thorpej */
1440 1.22 thorpej dcm->dcm_data[port].dcm_baud = ttspeedtab(rate, dcmspeedtab);
1441 1.22 thorpej dcm->dcm_data[port].dcm_conf = mode;
1442 1.22 thorpej SEM_LOCK(dcm);
1443 1.22 thorpej dcm->dcm_cmdtab[port].dcm_data |= CT_CON;
1444 1.22 thorpej dcm->dcm_cr |= (1 << port);
1445 1.22 thorpej SEM_UNLOCK(dcm);
1446 1.22 thorpej
1447 1.22 thorpej /*
1448 1.22 thorpej * Delay for config change to take place. Weighted by baud.
1449 1.22 thorpej * XXX why do we do this?
1450 1.22 thorpej */
1451 1.22 thorpej DELAY(16 * DCM_USPERCH(rate));
1452 1.22 thorpej splx(s);
1453 1.22 thorpej }
1454 1.22 thorpej
1455 1.1 cgd /*
1456 1.34 thorpej * Empirically derived self-test magic
1457 1.34 thorpej */
1458 1.65 thorpej static int
1459 1.65 thorpej dcmselftest(struct dcm_softc *sc)
1460 1.34 thorpej {
1461 1.34 thorpej struct dcmdevice *dcm = sc->sc_dcm;
1462 1.36 scottr int timo = 0;
1463 1.36 scottr int s, rv;
1464 1.34 thorpej
1465 1.35 thorpej rv = 1;
1466 1.35 thorpej
1467 1.35 thorpej s = splhigh();
1468 1.34 thorpej dcm->dcm_rsid = DCMRS;
1469 1.34 thorpej DELAY(50000); /* 5000 is not long enough */
1470 1.63 tsutsui dcm->dcm_rsid = 0;
1471 1.34 thorpej dcm->dcm_ic = IC_IE;
1472 1.34 thorpej dcm->dcm_cr = CR_SELFT;
1473 1.35 thorpej while ((dcm->dcm_ic & IC_IR) == 0) {
1474 1.34 thorpej if (++timo == 20000)
1475 1.35 thorpej goto out;
1476 1.35 thorpej DELAY(1);
1477 1.35 thorpej }
1478 1.34 thorpej DELAY(50000); /* XXX why is this needed ???? */
1479 1.35 thorpej while ((dcm->dcm_iir & IIR_SELFT) == 0) {
1480 1.34 thorpej if (++timo == 400000)
1481 1.35 thorpej goto out;
1482 1.35 thorpej DELAY(1);
1483 1.35 thorpej }
1484 1.34 thorpej DELAY(50000); /* XXX why is this needed ???? */
1485 1.34 thorpej if (dcm->dcm_stcon != ST_OK) {
1486 1.34 thorpej #if 0
1487 1.34 thorpej if (hd->hp_args->hw_sc != conscode)
1488 1.79 tsutsui aprint_error_dev(sc->sc_dev, "self test failed: %x\n",
1489 1.79 tsutsui dcm->dcm_stcon);
1490 1.34 thorpej #endif
1491 1.35 thorpej goto out;
1492 1.34 thorpej }
1493 1.34 thorpej dcm->dcm_ic = IC_ID;
1494 1.35 thorpej rv = 0;
1495 1.35 thorpej
1496 1.35 thorpej out:
1497 1.34 thorpej splx(s);
1498 1.72 tsutsui return rv;
1499 1.34 thorpej }
1500 1.34 thorpej
1501 1.34 thorpej /*
1502 1.1 cgd * Following are all routines needed for DCM to act as console
1503 1.1 cgd */
1504 1.1 cgd
1505 1.24 thorpej int
1506 1.48 gmcgarry dcmcnattach(bus_space_tag_t bst, bus_addr_t addr, int scode)
1507 1.1 cgd {
1508 1.59 gmcgarry bus_space_handle_t bsh;
1509 1.77 christos void *va;
1510 1.59 gmcgarry struct dcmdevice *dcm;
1511 1.52 gehenna int maj;
1512 1.48 gmcgarry
1513 1.59 gmcgarry if (bus_space_map(bst, addr, DIOCSIZE, 0, &bsh))
1514 1.72 tsutsui return 1;
1515 1.48 gmcgarry
1516 1.59 gmcgarry va = bus_space_vaddr(bst, bsh);
1517 1.48 gmcgarry dcm = (struct dcmdevice *)va;
1518 1.1 cgd
1519 1.20 thorpej switch (dcm->dcm_rsid) {
1520 1.48 gmcgarry #ifdef CONSCODE
1521 1.1 cgd case DCMID:
1522 1.48 gmcgarry #endif
1523 1.1 cgd case DCMID|DCMCON:
1524 1.1 cgd break;
1525 1.1 cgd default:
1526 1.48 gmcgarry goto error;
1527 1.22 thorpej }
1528 1.24 thorpej
1529 1.48 gmcgarry dcminit(dcm, DCMCONSPORT, dcmdefaultrate);
1530 1.59 gmcgarry dcmconsinit = 1;
1531 1.48 gmcgarry dcmconscode = scode;
1532 1.59 gmcgarry dcm_cn = dcm;
1533 1.48 gmcgarry
1534 1.59 gmcgarry /* locate the major number */
1535 1.59 gmcgarry maj = cdevsw_lookup_major(&dcm_cdevsw);
1536 1.48 gmcgarry
1537 1.59 gmcgarry /* initialize required fields */
1538 1.59 gmcgarry cn_tab = &dcm_cons;
1539 1.59 gmcgarry cn_tab->cn_dev = makedev(maj, 0);
1540 1.22 thorpej
1541 1.1 cgd #ifdef KGDB_CHEAT
1542 1.24 thorpej /* XXX this needs to be fixed. */
1543 1.1 cgd /*
1544 1.1 cgd * This doesn't currently work, at least not with ite consoles;
1545 1.1 cgd * the console hasn't been initialized yet.
1546 1.1 cgd */
1547 1.52 gehenna if (major(kgdb_dev) == maj &&
1548 1.20 thorpej DCMBOARD(DCMUNIT(kgdb_dev)) == DCMBOARD(unit)) {
1549 1.22 thorpej dcminit(dcm_cn, DCMPORT(DCMUNIT(kgdb_dev)), kgdb_rate);
1550 1.1 cgd if (kgdb_debug_init) {
1551 1.1 cgd /*
1552 1.1 cgd * We assume that console is ready for us...
1553 1.1 cgd * this assumes that a dca or ite console
1554 1.1 cgd * has been selected already and will init
1555 1.1 cgd * on the first putc.
1556 1.1 cgd */
1557 1.31 christos printf("dcm%d: ", DCMUNIT(kgdb_dev));
1558 1.1 cgd kgdb_connect(1);
1559 1.1 cgd }
1560 1.1 cgd }
1561 1.1 cgd #endif
1562 1.1 cgd
1563 1.20 thorpej
1564 1.72 tsutsui return 0;
1565 1.48 gmcgarry
1566 1.48 gmcgarry error:
1567 1.59 gmcgarry bus_space_unmap(bst, bsh, DIOCSIZE);
1568 1.72 tsutsui return 1;
1569 1.1 cgd }
1570 1.1 cgd
1571 1.24 thorpej /* ARGSUSED */
1572 1.65 thorpej static int
1573 1.65 thorpej dcmcngetc(dev_t dev)
1574 1.1 cgd {
1575 1.20 thorpej struct dcmrfifo *fifo;
1576 1.20 thorpej struct dcmpreg *pp;
1577 1.20 thorpej u_int head;
1578 1.24 thorpej int s, c, stat;
1579 1.22 thorpej
1580 1.24 thorpej pp = dcm_preg(dcm_cn, DCMCONSPORT);
1581 1.20 thorpej
1582 1.1 cgd s = splhigh();
1583 1.1 cgd head = pp->r_head & RX_MASK;
1584 1.24 thorpej fifo = &dcm_cn->dcm_rfifos[3-DCMCONSPORT][head>>1];
1585 1.1 cgd while (head == (pp->r_tail & RX_MASK))
1586 1.1 cgd ;
1587 1.1 cgd /*
1588 1.1 cgd * If board interrupts are enabled, just let our received char
1589 1.1 cgd * interrupt through in case some other port on the board was
1590 1.1 cgd * busy. Otherwise we must clear the interrupt.
1591 1.1 cgd */
1592 1.22 thorpej SEM_LOCK(dcm_cn);
1593 1.22 thorpej if ((dcm_cn->dcm_ic & IC_IE) == 0)
1594 1.22 thorpej stat = dcm_cn->dcm_iir;
1595 1.22 thorpej SEM_UNLOCK(dcm_cn);
1596 1.1 cgd c = fifo->data_char;
1597 1.1 cgd stat = fifo->data_stat;
1598 1.1 cgd pp->r_head = (head + 2) & RX_MASK;
1599 1.85 christos __USE(stat);
1600 1.1 cgd splx(s);
1601 1.72 tsutsui return c;
1602 1.1 cgd }
1603 1.1 cgd
1604 1.1 cgd /*
1605 1.1 cgd * Console kernel output character routine.
1606 1.1 cgd */
1607 1.24 thorpej /* ARGSUSED */
1608 1.65 thorpej static void
1609 1.65 thorpej dcmcnputc(dev_t dev, int c)
1610 1.1 cgd {
1611 1.20 thorpej struct dcmpreg *pp;
1612 1.1 cgd unsigned tail;
1613 1.36 scottr int s, stat;
1614 1.22 thorpej
1615 1.24 thorpej pp = dcm_preg(dcm_cn, DCMCONSPORT);
1616 1.20 thorpej
1617 1.1 cgd s = splhigh();
1618 1.1 cgd #ifdef KGDB
1619 1.1 cgd if (dev != kgdb_dev)
1620 1.1 cgd #endif
1621 1.1 cgd if (dcmconsinit == 0) {
1622 1.24 thorpej dcminit(dcm_cn, DCMCONSPORT, dcmdefaultrate);
1623 1.1 cgd dcmconsinit = 1;
1624 1.1 cgd }
1625 1.1 cgd tail = pp->t_tail & TX_MASK;
1626 1.1 cgd while (tail != (pp->t_head & TX_MASK))
1627 1.85 christos continue;
1628 1.24 thorpej dcm_cn->dcm_tfifos[3-DCMCONSPORT][tail].data_char = c;
1629 1.1 cgd pp->t_tail = tail = (tail + 1) & TX_MASK;
1630 1.22 thorpej SEM_LOCK(dcm_cn);
1631 1.24 thorpej dcm_cn->dcm_cmdtab[DCMCONSPORT].dcm_data |= CT_TX;
1632 1.24 thorpej dcm_cn->dcm_cr |= (1 << DCMCONSPORT);
1633 1.22 thorpej SEM_UNLOCK(dcm_cn);
1634 1.1 cgd while (tail != (pp->t_head & TX_MASK))
1635 1.85 christos continue;
1636 1.1 cgd /*
1637 1.1 cgd * If board interrupts are enabled, just let our completion
1638 1.1 cgd * interrupt through in case some other port on the board
1639 1.1 cgd * was busy. Otherwise we must clear the interrupt.
1640 1.1 cgd */
1641 1.22 thorpej if ((dcm_cn->dcm_ic & IC_IE) == 0) {
1642 1.22 thorpej SEM_LOCK(dcm_cn);
1643 1.22 thorpej stat = dcm_cn->dcm_iir;
1644 1.22 thorpej SEM_UNLOCK(dcm_cn);
1645 1.1 cgd }
1646 1.85 christos __USE(stat);
1647 1.1 cgd splx(s);
1648 1.1 cgd }
1649