dcm.c revision 1.87 1 1.87 dholland /* $NetBSD: dcm.c,v 1.87 2014/07/25 08:10:33 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.87 dholland __KERNEL_RCSID(0, "$NetBSD: dcm.c,v 1.87 2014/07/25 08:10:33 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.87 dholland .d_discard = nodiscard,
345 1.84 dholland .d_flag = D_TTY
346 1.52 gehenna };
347 1.52 gehenna
348 1.65 thorpej static int
349 1.79 tsutsui dcmmatch(device_t parent, cfdata_t cf, void *aux)
350 1.34 thorpej {
351 1.34 thorpej struct dio_attach_args *da = aux;
352 1.34 thorpej
353 1.34 thorpej switch (da->da_id) {
354 1.34 thorpej case DIO_DEVICE_ID_DCM:
355 1.34 thorpej case DIO_DEVICE_ID_DCMREM:
356 1.72 tsutsui return 1;
357 1.34 thorpej }
358 1.34 thorpej
359 1.72 tsutsui return 0;
360 1.34 thorpej }
361 1.20 thorpej
362 1.65 thorpej static void
363 1.79 tsutsui dcmattach(device_t parent, device_t self, void *aux)
364 1.34 thorpej {
365 1.79 tsutsui struct dcm_softc *sc = device_private(self);
366 1.34 thorpej struct dio_attach_args *da = aux;
367 1.34 thorpej struct dcmdevice *dcm;
368 1.69 thorpej int brd = device_unit(self);
369 1.34 thorpej int scode = da->da_scode;
370 1.59 gmcgarry int i, mbits, code;
371 1.20 thorpej
372 1.79 tsutsui sc->sc_dev = self;
373 1.36 scottr sc->sc_flags = 0;
374 1.36 scottr
375 1.48 gmcgarry if (scode == dcmconscode) {
376 1.48 gmcgarry dcm = dcm_cn;
377 1.24 thorpej sc->sc_flags |= DCM_ISCONSOLE;
378 1.24 thorpej
379 1.24 thorpej /*
380 1.24 thorpej * We didn't know which unit this would be during
381 1.24 thorpej * the console probe, so we have to fixup cn_dev here.
382 1.24 thorpej * Note that we always assume port 1 on the board.
383 1.24 thorpej */
384 1.52 gehenna cn_tab->cn_dev = makedev(cdevsw_lookup_major(&dcm_cdevsw),
385 1.79 tsutsui (brd << 2) | DCMCONSPORT);
386 1.34 thorpej } else {
387 1.59 gmcgarry sc->sc_bst = da->da_bst;
388 1.59 gmcgarry if (bus_space_map(sc->sc_bst, da->da_addr, da->da_size,
389 1.59 gmcgarry BUS_SPACE_MAP_LINEAR, &sc->sc_bsh)) {
390 1.79 tsutsui aprint_error(": can't map registers\n");
391 1.34 thorpej return;
392 1.34 thorpej }
393 1.79 tsutsui dcm = bus_space_vaddr(sc->sc_bst, sc->sc_bsh);
394 1.34 thorpej }
395 1.34 thorpej
396 1.34 thorpej sc->sc_dcm = dcm;
397 1.34 thorpej
398 1.38 scottr /*
399 1.38 scottr * XXX someone _should_ fix this; the self test screws
400 1.38 scottr * autoconfig messages.
401 1.38 scottr */
402 1.38 scottr if ((sc->sc_flags & DCM_ISCONSOLE) && dcmselftest(sc)) {
403 1.79 tsutsui aprint_normal("\n");
404 1.79 tsutsui aprint_error_dev(self, "self-test failed\n");
405 1.34 thorpej return;
406 1.24 thorpej }
407 1.20 thorpej
408 1.20 thorpej /* Extract configuration info from flags. */
409 1.70 thorpej sc->sc_softCAR = device_cfdata(self)->cf_flags & DCM_SOFTCAR;
410 1.70 thorpej sc->sc_flags |= device_cfdata(self)->cf_flags & DCM_FLAGMASK;
411 1.20 thorpej
412 1.20 thorpej /* Mark our unit as configured. */
413 1.20 thorpej sc->sc_flags |= DCM_ACTIVE;
414 1.20 thorpej
415 1.20 thorpej /* Establish the interrupt handler. */
416 1.79 tsutsui (void)dio_intr_establish(dcmintr, sc, da->da_ipl, IPL_TTY);
417 1.20 thorpej
418 1.1 cgd if (dcmistype == DIS_TIMER)
419 1.1 cgd dcmsetischeme(brd, DIS_RESET|DIS_TIMER);
420 1.1 cgd else
421 1.1 cgd dcmsetischeme(brd, DIS_RESET|DIS_PERCHAR);
422 1.1 cgd
423 1.1 cgd /* load pointers to modem control */
424 1.20 thorpej sc->sc_modem[0] = &dcm->dcm_modem0;
425 1.20 thorpej sc->sc_modem[1] = &dcm->dcm_modem1;
426 1.20 thorpej sc->sc_modem[2] = &dcm->dcm_modem2;
427 1.20 thorpej sc->sc_modem[3] = &dcm->dcm_modem3;
428 1.20 thorpej
429 1.1 cgd /* set DCD (modem) and CTS (flow control) on all ports */
430 1.20 thorpej if (sc->sc_flags & DCM_STDDCE)
431 1.1 cgd mbits = hp2dce_in(MI_CD|MI_CTS);
432 1.1 cgd else
433 1.1 cgd mbits = MI_CD|MI_CTS;
434 1.20 thorpej
435 1.20 thorpej for (i = 0; i < NDCMPORT; i++)
436 1.20 thorpej sc->sc_modem[i]->mdmmsk = mbits;
437 1.1 cgd
438 1.38 scottr /*
439 1.38 scottr * Get current state of mdmin register on all ports, so that
440 1.38 scottr * deltas will work properly.
441 1.38 scottr */
442 1.38 scottr for (i = 0; i < NDCMPORT; i++) {
443 1.38 scottr code = sc->sc_modem[i]->mdmin;
444 1.38 scottr if (sc->sc_flags & DCM_STDDCE)
445 1.38 scottr code = hp2dce_in(code);
446 1.38 scottr sc->sc_mcndlast[i] = code;
447 1.38 scottr }
448 1.38 scottr
449 1.1 cgd dcm->dcm_ic = IC_IE; /* turn all interrupts on */
450 1.20 thorpej
451 1.1 cgd /*
452 1.24 thorpej * Need to reset baud rate, etc. of next print so reset dcmconsinit.
453 1.1 cgd * Also make sure console is always "hardwired"
454 1.1 cgd */
455 1.24 thorpej if (sc->sc_flags & DCM_ISCONSOLE) {
456 1.1 cgd dcmconsinit = 0;
457 1.24 thorpej sc->sc_softCAR |= (1 << DCMCONSPORT);
458 1.79 tsutsui aprint_normal(": console on port %d\n", DCMCONSPORT);
459 1.20 thorpej } else
460 1.79 tsutsui aprint_normal("\n");
461 1.20 thorpej
462 1.20 thorpej #ifdef KGDB
463 1.52 gehenna if (cdevsw_lookup(kgdb_dev) == &dcm_cdevsw &&
464 1.20 thorpej DCMBOARD(DCMUNIT(kgdb_dev)) == brd) {
465 1.24 thorpej if (dcmconsole == DCMUNIT(kgdb_dev)) /* XXX fixme */
466 1.20 thorpej kgdb_dev = NODEV; /* can't debug over console port */
467 1.20 thorpej #ifndef KGDB_CHEAT
468 1.20 thorpej /*
469 1.20 thorpej * The following could potentially be replaced
470 1.20 thorpej * by the corresponding code in dcmcnprobe.
471 1.20 thorpej */
472 1.20 thorpej else {
473 1.22 thorpej dcminit(dcm, DCMPORT(DCMUNIT(kgdb_dev)),
474 1.22 thorpej kgdb_rate);
475 1.20 thorpej if (kgdb_debug_init) {
476 1.79 tsutsui aprint_normal_dev(self, "port %d: ",
477 1.20 thorpej DCMPORT(DCMUNIT(kgdb_dev)));
478 1.20 thorpej kgdb_connect(1);
479 1.20 thorpej } else
480 1.79 tsutsui aprint_normal_dev(self,
481 1.79 tsutsui "port %d: kgdb enabled\n",
482 1.20 thorpej DCMPORT(DCMUNIT(kgdb_dev)));
483 1.20 thorpej }
484 1.20 thorpej /* end could be replaced */
485 1.34 thorpej #endif /* KGDB_CHEAT */
486 1.1 cgd }
487 1.34 thorpej #endif /* KGDB */
488 1.1 cgd }
489 1.1 cgd
490 1.1 cgd /* ARGSUSED */
491 1.65 thorpej static int
492 1.68 christos dcmopen(dev_t dev, int flag, int mode, struct lwp *l)
493 1.1 cgd {
494 1.20 thorpej struct dcm_softc *sc;
495 1.20 thorpej struct tty *tp;
496 1.20 thorpej int unit, brd, port;
497 1.18 thorpej int error = 0, mbits, s;
498 1.1 cgd
499 1.20 thorpej unit = DCMUNIT(dev);
500 1.20 thorpej brd = DCMBOARD(unit);
501 1.20 thorpej port = DCMPORT(unit);
502 1.20 thorpej
503 1.81 cegger sc = device_lookup_private(&dcm_cd, brd);
504 1.81 cegger if (sc == NULL)
505 1.72 tsutsui return ENXIO;
506 1.20 thorpej
507 1.20 thorpej if ((sc->sc_flags & DCM_ACTIVE) == 0)
508 1.72 tsutsui return ENXIO;
509 1.20 thorpej
510 1.28 thorpej if (sc->sc_tty[port] == NULL) {
511 1.83 rmind tp = sc->sc_tty[port] = tty_alloc();
512 1.28 thorpej tty_attach(tp);
513 1.28 thorpej } else
514 1.20 thorpej tp = sc->sc_tty[port];
515 1.20 thorpej
516 1.1 cgd tp->t_oproc = dcmstart;
517 1.1 cgd tp->t_param = dcmparam;
518 1.1 cgd tp->t_dev = dev;
519 1.18 thorpej
520 1.76 elad if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
521 1.75 elad return (EBUSY);
522 1.44 thorpej
523 1.44 thorpej s = spltty();
524 1.44 thorpej
525 1.44 thorpej if ((tp->t_state & TS_ISOPEN) == 0 && tp->t_wopen == 0) {
526 1.18 thorpej /*
527 1.18 thorpej * Sanity clause: reset the card on first open.
528 1.18 thorpej * The card might be left in an inconsistent state
529 1.18 thorpej * if the card memory is read inadvertently.
530 1.18 thorpej */
531 1.22 thorpej dcminit(sc->sc_dcm, port, dcmdefaultrate);
532 1.18 thorpej
533 1.1 cgd ttychars(tp);
534 1.18 thorpej tp->t_iflag = TTYDEF_IFLAG;
535 1.18 thorpej tp->t_oflag = TTYDEF_OFLAG;
536 1.18 thorpej tp->t_cflag = TTYDEF_CFLAG;
537 1.18 thorpej tp->t_lflag = TTYDEF_LFLAG;
538 1.18 thorpej tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
539 1.18 thorpej
540 1.1 cgd (void) dcmparam(tp, &tp->t_termios);
541 1.1 cgd ttsetwater(tp);
542 1.18 thorpej
543 1.44 thorpej /* Set modem control state. */
544 1.44 thorpej mbits = MO_ON;
545 1.44 thorpej if (sc->sc_flags & DCM_STDDCE)
546 1.44 thorpej mbits |= MO_SR; /* pin 23, could be used as RTS */
547 1.44 thorpej
548 1.44 thorpej (void) dcmmctl(dev, mbits, DMSET); /* enable port */
549 1.20 thorpej
550 1.44 thorpej /* Set soft-carrier if so configured. */
551 1.44 thorpej if ((sc->sc_softCAR & (1 << port)) ||
552 1.44 thorpej (dcmmctl(dev, MO_OFF, DMGET) & MI_CD))
553 1.44 thorpej tp->t_state |= TS_CARR_ON;
554 1.44 thorpej }
555 1.18 thorpej
556 1.44 thorpej splx(s);
557 1.18 thorpej
558 1.1 cgd #ifdef DEBUG
559 1.1 cgd if (dcmdebug & DDB_MODEM)
560 1.31 christos printf("%s: dcmopen port %d softcarr %c\n",
561 1.79 tsutsui device_xname(sc->sc_dev), port,
562 1.79 tsutsui (tp->t_state & TS_CARR_ON) ? '1' : '0');
563 1.1 cgd #endif
564 1.18 thorpej
565 1.44 thorpej error = ttyopen(tp, DCMDIALOUT(dev), (flag & O_NONBLOCK));
566 1.44 thorpej if (error)
567 1.44 thorpej goto bad;
568 1.1 cgd
569 1.1 cgd #ifdef DEBUG
570 1.1 cgd if (dcmdebug & DDB_OPENCLOSE)
571 1.31 christos printf("%s port %d: dcmopen: st %x fl %x\n",
572 1.79 tsutsui device_xname(sc->sc_dev), port, tp->t_state, tp->t_flags);
573 1.1 cgd #endif
574 1.45 eeh error = (*tp->t_linesw->l_open)(dev, tp);
575 1.18 thorpej
576 1.44 thorpej bad:
577 1.72 tsutsui return error;
578 1.1 cgd }
579 1.63 tsutsui
580 1.1 cgd /*ARGSUSED*/
581 1.65 thorpej static int
582 1.68 christos dcmclose(dev_t dev, int flag, int mode, struct lwp *l)
583 1.1 cgd {
584 1.20 thorpej int s, unit, board, port;
585 1.20 thorpej struct dcm_softc *sc;
586 1.20 thorpej struct tty *tp;
587 1.63 tsutsui
588 1.20 thorpej unit = DCMUNIT(dev);
589 1.20 thorpej board = DCMBOARD(unit);
590 1.20 thorpej port = DCMPORT(unit);
591 1.20 thorpej
592 1.81 cegger sc = device_lookup_private(&dcm_cd,board);
593 1.20 thorpej tp = sc->sc_tty[port];
594 1.20 thorpej
595 1.45 eeh (*tp->t_linesw->l_close)(tp, flag);
596 1.18 thorpej
597 1.18 thorpej s = spltty();
598 1.18 thorpej
599 1.44 thorpej if (tp->t_cflag & HUPCL || tp->t_wopen != 0 ||
600 1.18 thorpej (tp->t_state & TS_ISOPEN) == 0)
601 1.1 cgd (void) dcmmctl(dev, MO_OFF, DMSET);
602 1.1 cgd #ifdef DEBUG
603 1.1 cgd if (dcmdebug & DDB_OPENCLOSE)
604 1.31 christos printf("%s port %d: dcmclose: st %x fl %x\n",
605 1.79 tsutsui device_xname(sc->sc_dev), port, tp->t_state, tp->t_flags);
606 1.1 cgd #endif
607 1.18 thorpej splx(s);
608 1.1 cgd ttyclose(tp);
609 1.12 mycroft #if 0
610 1.28 thorpej tty_detach(tp);
611 1.83 rmind tty_free(tp);
612 1.20 thorpej sc->sc_tty[port] == NULL;
613 1.12 mycroft #endif
614 1.72 tsutsui return 0;
615 1.1 cgd }
616 1.63 tsutsui
617 1.65 thorpej static int
618 1.65 thorpej dcmread(dev_t dev, struct uio *uio, int flag)
619 1.1 cgd {
620 1.20 thorpej int unit, board, port;
621 1.20 thorpej struct dcm_softc *sc;
622 1.36 scottr struct tty *tp;
623 1.20 thorpej
624 1.20 thorpej unit = DCMUNIT(dev);
625 1.20 thorpej board = DCMBOARD(unit);
626 1.20 thorpej port = DCMPORT(unit);
627 1.20 thorpej
628 1.81 cegger sc = device_lookup_private(&dcm_cd,board);
629 1.20 thorpej tp = sc->sc_tty[port];
630 1.14 mycroft
631 1.72 tsutsui return (*tp->t_linesw->l_read)(tp, uio, flag);
632 1.1 cgd }
633 1.63 tsutsui
634 1.65 thorpej static int
635 1.65 thorpej dcmwrite(dev_t dev, struct uio *uio, int flag)
636 1.1 cgd {
637 1.20 thorpej int unit, board, port;
638 1.20 thorpej struct dcm_softc *sc;
639 1.36 scottr struct tty *tp;
640 1.20 thorpej
641 1.20 thorpej unit = DCMUNIT(dev);
642 1.20 thorpej board = DCMBOARD(unit);
643 1.20 thorpej port = DCMPORT(unit);
644 1.20 thorpej
645 1.81 cegger sc = device_lookup_private(&dcm_cd, board);
646 1.20 thorpej tp = sc->sc_tty[port];
647 1.14 mycroft
648 1.72 tsutsui return (*tp->t_linesw->l_write)(tp, uio, flag);
649 1.46 scw }
650 1.46 scw
651 1.65 thorpej static int
652 1.68 christos dcmpoll(dev_t dev, int events, struct lwp *l)
653 1.46 scw {
654 1.46 scw int unit, board, port;
655 1.46 scw struct dcm_softc *sc;
656 1.46 scw struct tty *tp;
657 1.46 scw
658 1.46 scw unit = DCMUNIT(dev);
659 1.46 scw board = DCMBOARD(unit);
660 1.46 scw port = DCMPORT(unit);
661 1.46 scw
662 1.81 cegger sc = device_lookup_private(&dcm_cd, board);
663 1.46 scw tp = sc->sc_tty[port];
664 1.63 tsutsui
665 1.72 tsutsui return (*tp->t_linesw->l_poll)(tp, events, l);
666 1.1 cgd }
667 1.17 mycroft
668 1.65 thorpej static struct tty *
669 1.65 thorpej dcmtty(dev_t dev)
670 1.17 mycroft {
671 1.20 thorpej int unit, board, port;
672 1.20 thorpej struct dcm_softc *sc;
673 1.17 mycroft
674 1.20 thorpej unit = DCMUNIT(dev);
675 1.20 thorpej board = DCMBOARD(unit);
676 1.20 thorpej port = DCMPORT(unit);
677 1.20 thorpej
678 1.81 cegger sc = device_lookup_private(&dcm_cd, board);
679 1.20 thorpej
680 1.72 tsutsui return sc->sc_tty[port];
681 1.17 mycroft }
682 1.63 tsutsui
683 1.65 thorpej static int
684 1.65 thorpej dcmintr(void *arg)
685 1.1 cgd {
686 1.23 thorpej struct dcm_softc *sc = arg;
687 1.20 thorpej struct dcmdevice *dcm = sc->sc_dcm;
688 1.20 thorpej struct dcmischeme *dis = &sc->sc_scheme;
689 1.79 tsutsui int brd = device_unit(sc->sc_dev);
690 1.20 thorpej int code, i;
691 1.1 cgd int pcnd[4], mcode, mcnd[4];
692 1.1 cgd
693 1.1 cgd /*
694 1.36 scottr * Do all guarded accesses right off to minimize
695 1.1 cgd * block out of hardware.
696 1.1 cgd */
697 1.1 cgd SEM_LOCK(dcm);
698 1.1 cgd if ((dcm->dcm_ic & IC_IR) == 0) {
699 1.1 cgd SEM_UNLOCK(dcm);
700 1.72 tsutsui return 0;
701 1.1 cgd }
702 1.1 cgd for (i = 0; i < 4; i++) {
703 1.1 cgd pcnd[i] = dcm->dcm_icrtab[i].dcm_data;
704 1.1 cgd dcm->dcm_icrtab[i].dcm_data = 0;
705 1.20 thorpej code = sc->sc_modem[i]->mdmin;
706 1.20 thorpej if (sc->sc_flags & DCM_STDDCE)
707 1.1 cgd code = hp2dce_in(code);
708 1.1 cgd mcnd[i] = code;
709 1.1 cgd }
710 1.1 cgd code = dcm->dcm_iir & IIR_MASK;
711 1.1 cgd dcm->dcm_iir = 0; /* XXX doc claims read clears interrupt?! */
712 1.1 cgd mcode = dcm->dcm_modemintr;
713 1.1 cgd dcm->dcm_modemintr = 0;
714 1.1 cgd SEM_UNLOCK(dcm);
715 1.1 cgd
716 1.1 cgd #ifdef DEBUG
717 1.1 cgd if (dcmdebug & DDB_INTR) {
718 1.31 christos printf("%s: dcmintr: iir %x pc %x/%x/%x/%x ",
719 1.79 tsutsui device_xname(sc->sc_dev), code, pcnd[0], pcnd[1],
720 1.79 tsutsui pcnd[2], pcnd[3]);
721 1.31 christos printf("miir %x mc %x/%x/%x/%x\n",
722 1.79 tsutsui mcode, mcnd[0], mcnd[1], mcnd[2], mcnd[3]);
723 1.1 cgd }
724 1.1 cgd #endif
725 1.1 cgd if (code & IIR_TIMEO)
726 1.20 thorpej dcmrint(sc);
727 1.1 cgd if (code & IIR_PORT0)
728 1.20 thorpej dcmpint(sc, 0, pcnd[0]);
729 1.1 cgd if (code & IIR_PORT1)
730 1.20 thorpej dcmpint(sc, 1, pcnd[1]);
731 1.1 cgd if (code & IIR_PORT2)
732 1.20 thorpej dcmpint(sc, 2, pcnd[2]);
733 1.1 cgd if (code & IIR_PORT3)
734 1.20 thorpej dcmpint(sc, 3, pcnd[3]);
735 1.1 cgd if (code & IIR_MODM) {
736 1.1 cgd if (mcode == 0 || mcode & 0x1) /* mcode==0 -> 98642 board */
737 1.20 thorpej dcmmint(sc, 0, mcnd[0]);
738 1.1 cgd if (mcode & 0x2)
739 1.20 thorpej dcmmint(sc, 1, mcnd[1]);
740 1.1 cgd if (mcode & 0x4)
741 1.20 thorpej dcmmint(sc, 2, mcnd[2]);
742 1.1 cgd if (mcode & 0x8)
743 1.20 thorpej dcmmint(sc, 3, mcnd[3]);
744 1.1 cgd }
745 1.1 cgd
746 1.1 cgd /*
747 1.1 cgd * Chalk up a receiver interrupt if the timer running or one of
748 1.1 cgd * the ports reports a special character interrupt.
749 1.1 cgd */
750 1.1 cgd if ((code & IIR_TIMEO) ||
751 1.1 cgd ((pcnd[0]|pcnd[1]|pcnd[2]|pcnd[3]) & IT_SPEC))
752 1.1 cgd dis->dis_intr++;
753 1.1 cgd /*
754 1.1 cgd * See if it is time to check/change the interrupt rate.
755 1.1 cgd */
756 1.1 cgd if (dcmistype < 0 &&
757 1.74 tsutsui (i = time_second - dis->dis_time) >= dcminterval) {
758 1.1 cgd /*
759 1.1 cgd * If currently per-character and averaged over 70 interrupts
760 1.1 cgd * per-second (66 is threshold of 600 baud) in last interval,
761 1.1 cgd * switch to timer mode.
762 1.1 cgd *
763 1.1 cgd * XXX decay counts ala load average to avoid spikes?
764 1.1 cgd */
765 1.1 cgd if (dis->dis_perchar && dis->dis_intr > 70 * i)
766 1.1 cgd dcmsetischeme(brd, DIS_TIMER);
767 1.1 cgd /*
768 1.1 cgd * If currently using timer and had more interrupts than
769 1.1 cgd * received characters in the last interval, switch back
770 1.1 cgd * to per-character. Note that after changing to per-char
771 1.1 cgd * we must process any characters already in the queue
772 1.1 cgd * since they may have arrived before the bitmap was setup.
773 1.1 cgd *
774 1.1 cgd * XXX decay counts?
775 1.1 cgd */
776 1.1 cgd else if (!dis->dis_perchar && dis->dis_intr > dis->dis_char) {
777 1.1 cgd dcmsetischeme(brd, DIS_PERCHAR);
778 1.20 thorpej dcmrint(sc);
779 1.1 cgd }
780 1.1 cgd dis->dis_intr = dis->dis_char = 0;
781 1.74 tsutsui dis->dis_time = time_second;
782 1.1 cgd }
783 1.72 tsutsui return 1;
784 1.1 cgd }
785 1.1 cgd
786 1.1 cgd /*
787 1.1 cgd * Port interrupt. Can be two things:
788 1.1 cgd * First, it might be a special character (exception interrupt);
789 1.1 cgd * Second, it may be a buffer empty (transmit interrupt);
790 1.1 cgd */
791 1.65 thorpej static void
792 1.65 thorpej dcmpint(struct dcm_softc *sc, int port, int code)
793 1.1 cgd {
794 1.1 cgd
795 1.1 cgd if (code & IT_SPEC)
796 1.20 thorpej dcmreadbuf(sc, port);
797 1.1 cgd if (code & IT_TX)
798 1.20 thorpej dcmxint(sc, port);
799 1.1 cgd }
800 1.1 cgd
801 1.65 thorpej static void
802 1.65 thorpej dcmrint(struct dcm_softc *sc)
803 1.1 cgd {
804 1.20 thorpej int port;
805 1.1 cgd
806 1.20 thorpej for (port = 0; port < NDCMPORT; port++)
807 1.20 thorpej dcmreadbuf(sc, port);
808 1.1 cgd }
809 1.1 cgd
810 1.65 thorpej static void
811 1.65 thorpej dcmreadbuf(struct dcm_softc *sc, int port)
812 1.1 cgd {
813 1.20 thorpej struct dcmdevice *dcm = sc->sc_dcm;
814 1.20 thorpej struct dcmpreg *pp = dcm_preg(dcm, port);
815 1.20 thorpej struct dcmrfifo *fifo;
816 1.38 scottr struct tty *tp;
817 1.20 thorpej int c, stat;
818 1.20 thorpej u_int head;
819 1.1 cgd int nch = 0;
820 1.14 mycroft #ifdef DCMSTATS
821 1.20 thorpej struct dcmstats *dsp = &sc->sc_stats;
822 1.1 cgd
823 1.1 cgd dsp->rints++;
824 1.1 cgd #endif
825 1.38 scottr tp = sc->sc_tty[port];
826 1.40 scottr if (tp == NULL)
827 1.38 scottr return;
828 1.38 scottr
829 1.1 cgd if ((tp->t_state & TS_ISOPEN) == 0) {
830 1.1 cgd #ifdef KGDB
831 1.52 gehenna int maj;
832 1.52 gehenna
833 1.52 gehenna maj = cdevsw_lookup_major(&dcm_cdevsw);
834 1.52 gehenna
835 1.52 gehenna if ((makedev(maj, minor(tp->t_dev)) == kgdb_dev) &&
836 1.1 cgd (head = pp->r_head & RX_MASK) != (pp->r_tail & RX_MASK) &&
837 1.14 mycroft dcm->dcm_rfifos[3-port][head>>1].data_char == FRAME_START) {
838 1.1 cgd pp->r_head = (head + 2) & RX_MASK;
839 1.1 cgd kgdb_connect(0); /* trap into kgdb */
840 1.1 cgd return;
841 1.1 cgd }
842 1.1 cgd #endif /* KGDB */
843 1.1 cgd pp->r_head = pp->r_tail & RX_MASK;
844 1.1 cgd return;
845 1.1 cgd }
846 1.1 cgd
847 1.1 cgd head = pp->r_head & RX_MASK;
848 1.1 cgd fifo = &dcm->dcm_rfifos[3-port][head>>1];
849 1.1 cgd /*
850 1.1 cgd * XXX upper bound on how many chars we will take in one swallow?
851 1.1 cgd */
852 1.1 cgd while (head != (pp->r_tail & RX_MASK)) {
853 1.1 cgd /*
854 1.1 cgd * Get character/status and update head pointer as fast
855 1.1 cgd * as possible to make room for more characters.
856 1.1 cgd */
857 1.1 cgd c = fifo->data_char;
858 1.1 cgd stat = fifo->data_stat;
859 1.1 cgd head = (head + 2) & RX_MASK;
860 1.1 cgd pp->r_head = head;
861 1.1 cgd fifo = head ? fifo+1 : &dcm->dcm_rfifos[3-port][0];
862 1.1 cgd nch++;
863 1.1 cgd
864 1.1 cgd #ifdef DEBUG
865 1.1 cgd if (dcmdebug & DDB_INPUT)
866 1.79 tsutsui printf("%s port %d: "
867 1.79 tsutsui "dcmreadbuf: c%x('%c') s%x f%x h%x t%x\n",
868 1.79 tsutsui device_xname(sc->sc_dev), port,
869 1.79 tsutsui c&0xFF, c, stat&0xFF,
870 1.79 tsutsui tp->t_flags, head, pp->r_tail);
871 1.1 cgd #endif
872 1.1 cgd /*
873 1.1 cgd * Check for and handle errors
874 1.1 cgd */
875 1.1 cgd if (stat & RD_MASK) {
876 1.1 cgd #ifdef DEBUG
877 1.1 cgd if (dcmdebug & (DDB_INPUT|DDB_SIOERR))
878 1.79 tsutsui printf("%s port %d: "
879 1.79 tsutsui "dcmreadbuf: err: c%x('%c') s%x\n",
880 1.79 tsutsui device_xname(sc->sc_dev), port,
881 1.79 tsutsui stat, c&0xFF, c);
882 1.1 cgd #endif
883 1.1 cgd if (stat & (RD_BD | RD_FE))
884 1.1 cgd c |= TTY_FE;
885 1.1 cgd else if (stat & RD_PE)
886 1.1 cgd c |= TTY_PE;
887 1.1 cgd else if (stat & RD_OVF)
888 1.1 cgd log(LOG_WARNING,
889 1.20 thorpej "%s port %d: silo overflow\n",
890 1.79 tsutsui device_xname(sc->sc_dev), port);
891 1.1 cgd else if (stat & RD_OE)
892 1.1 cgd log(LOG_WARNING,
893 1.20 thorpej "%s port %d: uart overflow\n",
894 1.79 tsutsui device_xname(sc->sc_dev), port);
895 1.1 cgd }
896 1.45 eeh (*tp->t_linesw->l_rint)(c, tp);
897 1.1 cgd }
898 1.20 thorpej sc->sc_scheme.dis_char += nch;
899 1.20 thorpej
900 1.14 mycroft #ifdef DCMSTATS
901 1.1 cgd dsp->rchars += nch;
902 1.1 cgd if (nch <= DCMRBSIZE)
903 1.1 cgd dsp->rsilo[nch]++;
904 1.1 cgd else
905 1.1 cgd dsp->rsilo[DCMRBSIZE+1]++;
906 1.1 cgd #endif
907 1.1 cgd }
908 1.1 cgd
909 1.65 thorpej static void
910 1.65 thorpej dcmxint(struct dcm_softc *sc, int port)
911 1.1 cgd {
912 1.38 scottr struct tty *tp;
913 1.38 scottr
914 1.38 scottr tp = sc->sc_tty[port];
915 1.38 scottr if (tp == NULL || (tp->t_state & TS_ISOPEN) == 0)
916 1.38 scottr return;
917 1.20 thorpej
918 1.1 cgd tp->t_state &= ~TS_BUSY;
919 1.1 cgd if (tp->t_state & TS_FLUSH)
920 1.1 cgd tp->t_state &= ~TS_FLUSH;
921 1.45 eeh (*tp->t_linesw->l_start)(tp);
922 1.1 cgd }
923 1.1 cgd
924 1.65 thorpej static void
925 1.65 thorpej dcmmint(struct dcm_softc *sc, int port, int mcnd)
926 1.1 cgd {
927 1.1 cgd int delta;
928 1.20 thorpej struct tty *tp;
929 1.20 thorpej struct dcmdevice *dcm = sc->sc_dcm;
930 1.20 thorpej
931 1.1 cgd #ifdef DEBUG
932 1.1 cgd if (dcmdebug & DDB_MODEM)
933 1.31 christos printf("%s port %d: dcmmint: mcnd %x mcndlast %x\n",
934 1.79 tsutsui device_xname(sc->sc_dev), port, mcnd,
935 1.79 tsutsui sc->sc_mcndlast[port]);
936 1.1 cgd #endif
937 1.20 thorpej delta = mcnd ^ sc->sc_mcndlast[port];
938 1.20 thorpej sc->sc_mcndlast[port] = mcnd;
939 1.58 gmcgarry tp = sc->sc_tty[port];
940 1.58 gmcgarry if (tp == NULL || (tp->t_state & TS_ISOPEN) == 0)
941 1.58 gmcgarry return;
942 1.58 gmcgarry
943 1.1 cgd if ((delta & MI_CTS) && (tp->t_state & TS_ISOPEN) &&
944 1.55 gmcgarry (tp->t_cflag & CCTS_OFLOW)) {
945 1.1 cgd if (mcnd & MI_CTS) {
946 1.1 cgd tp->t_state &= ~TS_TTSTOP;
947 1.1 cgd ttstart(tp);
948 1.1 cgd } else
949 1.1 cgd tp->t_state |= TS_TTSTOP; /* inline dcmstop */
950 1.1 cgd }
951 1.1 cgd if (delta & MI_CD) {
952 1.1 cgd if (mcnd & MI_CD)
953 1.45 eeh (void)(*tp->t_linesw->l_modem)(tp, 1);
954 1.20 thorpej else if ((sc->sc_softCAR & (1 << port)) == 0 &&
955 1.45 eeh (*tp->t_linesw->l_modem)(tp, 0) == 0) {
956 1.20 thorpej sc->sc_modem[port]->mdmout = MO_OFF;
957 1.1 cgd SEM_LOCK(dcm);
958 1.20 thorpej dcm->dcm_modemchng |= (1 << port);
959 1.1 cgd dcm->dcm_cr |= CR_MODM;
960 1.1 cgd SEM_UNLOCK(dcm);
961 1.1 cgd DELAY(10); /* time to change lines */
962 1.1 cgd }
963 1.1 cgd }
964 1.1 cgd }
965 1.1 cgd
966 1.65 thorpej static int
967 1.77 christos dcmioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
968 1.1 cgd {
969 1.20 thorpej struct dcm_softc *sc;
970 1.20 thorpej struct tty *tp;
971 1.20 thorpej struct dcmdevice *dcm;
972 1.20 thorpej int board, port, unit = DCMUNIT(dev);
973 1.1 cgd int error, s;
974 1.20 thorpej
975 1.20 thorpej port = DCMPORT(unit);
976 1.20 thorpej board = DCMBOARD(unit);
977 1.20 thorpej
978 1.81 cegger sc = device_lookup_private(&dcm_cd, board);
979 1.20 thorpej dcm = sc->sc_dcm;
980 1.20 thorpej tp = sc->sc_tty[port];
981 1.63 tsutsui
982 1.1 cgd #ifdef DEBUG
983 1.1 cgd if (dcmdebug & DDB_IOCTL)
984 1.37 scottr printf("%s port %d: dcmioctl: cmd %lx data %x flag %x\n",
985 1.79 tsutsui device_xname(sc->sc_dev), port, cmd, *(int *)data, flag);
986 1.1 cgd #endif
987 1.51 atatat
988 1.68 christos error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
989 1.51 atatat if (error != EPASSTHROUGH)
990 1.72 tsutsui return error;
991 1.51 atatat
992 1.68 christos error = ttioctl(tp, cmd, data, flag, l);
993 1.51 atatat if (error != EPASSTHROUGH)
994 1.72 tsutsui return error;
995 1.1 cgd
996 1.1 cgd switch (cmd) {
997 1.1 cgd case TIOCSBRK:
998 1.1 cgd /*
999 1.1 cgd * Wait for transmitter buffer to empty
1000 1.1 cgd */
1001 1.1 cgd s = spltty();
1002 1.1 cgd while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)
1003 1.1 cgd DELAY(DCM_USPERCH(tp->t_ospeed));
1004 1.1 cgd SEM_LOCK(dcm);
1005 1.1 cgd dcm->dcm_cmdtab[port].dcm_data |= CT_BRK;
1006 1.1 cgd dcm->dcm_cr |= (1 << port); /* start break */
1007 1.1 cgd SEM_UNLOCK(dcm);
1008 1.1 cgd splx(s);
1009 1.1 cgd break;
1010 1.1 cgd
1011 1.1 cgd case TIOCCBRK:
1012 1.1 cgd SEM_LOCK(dcm);
1013 1.1 cgd dcm->dcm_cmdtab[port].dcm_data |= CT_BRK;
1014 1.1 cgd dcm->dcm_cr |= (1 << port); /* end break */
1015 1.1 cgd SEM_UNLOCK(dcm);
1016 1.1 cgd break;
1017 1.1 cgd
1018 1.1 cgd case TIOCSDTR:
1019 1.1 cgd (void) dcmmctl(dev, MO_ON, DMBIS);
1020 1.1 cgd break;
1021 1.1 cgd
1022 1.1 cgd case TIOCCDTR:
1023 1.1 cgd (void) dcmmctl(dev, MO_ON, DMBIC);
1024 1.1 cgd break;
1025 1.1 cgd
1026 1.1 cgd case TIOCMSET:
1027 1.1 cgd (void) dcmmctl(dev, *(int *)data, DMSET);
1028 1.1 cgd break;
1029 1.1 cgd
1030 1.1 cgd case TIOCMBIS:
1031 1.1 cgd (void) dcmmctl(dev, *(int *)data, DMBIS);
1032 1.1 cgd break;
1033 1.1 cgd
1034 1.1 cgd case TIOCMBIC:
1035 1.1 cgd (void) dcmmctl(dev, *(int *)data, DMBIC);
1036 1.1 cgd break;
1037 1.1 cgd
1038 1.1 cgd case TIOCMGET:
1039 1.1 cgd *(int *)data = dcmmctl(dev, 0, DMGET);
1040 1.1 cgd break;
1041 1.18 thorpej
1042 1.18 thorpej case TIOCGFLAGS: {
1043 1.18 thorpej int bits = 0;
1044 1.18 thorpej
1045 1.20 thorpej if ((sc->sc_softCAR & (1 << port)))
1046 1.18 thorpej bits |= TIOCFLAG_SOFTCAR;
1047 1.18 thorpej
1048 1.18 thorpej if (tp->t_cflag & CLOCAL)
1049 1.18 thorpej bits |= TIOCFLAG_CLOCAL;
1050 1.18 thorpej
1051 1.18 thorpej *(int *)data = bits;
1052 1.18 thorpej break;
1053 1.18 thorpej }
1054 1.18 thorpej
1055 1.18 thorpej case TIOCSFLAGS: {
1056 1.18 thorpej int userbits;
1057 1.18 thorpej
1058 1.75 elad if (kauth_authorize_device_tty(l->l_cred,
1059 1.75 elad KAUTH_DEVICE_TTY_PRIVSET, tp))
1060 1.75 elad return (EPERM);
1061 1.18 thorpej
1062 1.18 thorpej userbits = *(int *)data;
1063 1.18 thorpej
1064 1.18 thorpej if ((userbits & TIOCFLAG_SOFTCAR) ||
1065 1.24 thorpej ((sc->sc_flags & DCM_ISCONSOLE) &&
1066 1.24 thorpej (port == DCMCONSPORT)))
1067 1.20 thorpej sc->sc_softCAR |= (1 << port);
1068 1.18 thorpej
1069 1.18 thorpej if (userbits & TIOCFLAG_CLOCAL)
1070 1.18 thorpej tp->t_cflag |= CLOCAL;
1071 1.18 thorpej
1072 1.18 thorpej break;
1073 1.18 thorpej }
1074 1.1 cgd
1075 1.1 cgd default:
1076 1.72 tsutsui return EPASSTHROUGH;
1077 1.1 cgd }
1078 1.72 tsutsui return 0;
1079 1.1 cgd }
1080 1.1 cgd
1081 1.65 thorpej static int
1082 1.65 thorpej dcmparam(struct tty *tp, struct termios *t)
1083 1.1 cgd {
1084 1.20 thorpej struct dcm_softc *sc;
1085 1.20 thorpej struct dcmdevice *dcm;
1086 1.20 thorpej int unit, board, port, mode, cflag = t->c_cflag;
1087 1.1 cgd int ospeed = ttspeedtab(t->c_ospeed, dcmspeedtab);
1088 1.1 cgd
1089 1.20 thorpej unit = DCMUNIT(tp->t_dev);
1090 1.20 thorpej board = DCMBOARD(unit);
1091 1.20 thorpej port = DCMPORT(unit);
1092 1.20 thorpej
1093 1.81 cegger sc = device_lookup_private(&dcm_cd, board);
1094 1.20 thorpej dcm = sc->sc_dcm;
1095 1.20 thorpej
1096 1.1 cgd /* check requested parameters */
1097 1.59 gmcgarry if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
1098 1.72 tsutsui return EINVAL;
1099 1.59 gmcgarry /* and copy to tty */
1100 1.59 gmcgarry tp->t_ispeed = t->c_ispeed;
1101 1.59 gmcgarry tp->t_ospeed = t->c_ospeed;
1102 1.59 gmcgarry tp->t_cflag = cflag;
1103 1.1 cgd if (ospeed == 0) {
1104 1.72 tsutsui (void)dcmmctl(DCMUNIT(tp->t_dev), MO_OFF, DMSET);
1105 1.72 tsutsui return 0;
1106 1.1 cgd }
1107 1.1 cgd
1108 1.1 cgd mode = 0;
1109 1.1 cgd switch (cflag&CSIZE) {
1110 1.1 cgd case CS5:
1111 1.1 cgd mode = LC_5BITS; break;
1112 1.1 cgd case CS6:
1113 1.1 cgd mode = LC_6BITS; break;
1114 1.1 cgd case CS7:
1115 1.1 cgd mode = LC_7BITS; break;
1116 1.1 cgd case CS8:
1117 1.1 cgd mode = LC_8BITS; break;
1118 1.1 cgd }
1119 1.1 cgd if (cflag&PARENB) {
1120 1.1 cgd if (cflag&PARODD)
1121 1.1 cgd mode |= LC_PODD;
1122 1.1 cgd else
1123 1.1 cgd mode |= LC_PEVEN;
1124 1.1 cgd }
1125 1.1 cgd if (cflag&CSTOPB)
1126 1.1 cgd mode |= LC_2STOP;
1127 1.1 cgd else
1128 1.1 cgd mode |= LC_1STOP;
1129 1.1 cgd #ifdef DEBUG
1130 1.1 cgd if (dcmdebug & DDB_PARAM)
1131 1.79 tsutsui printf("%s port %d: "
1132 1.79 tsutsui "dcmparam: cflag %x mode %x speed %d uperch %d\n",
1133 1.79 tsutsui device_xname(sc->sc_dev), port, cflag, mode, tp->t_ospeed,
1134 1.79 tsutsui DCM_USPERCH(tp->t_ospeed));
1135 1.1 cgd #endif
1136 1.1 cgd
1137 1.1 cgd /*
1138 1.1 cgd * Wait for transmitter buffer to empty.
1139 1.1 cgd */
1140 1.1 cgd while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)
1141 1.1 cgd DELAY(DCM_USPERCH(tp->t_ospeed));
1142 1.1 cgd /*
1143 1.1 cgd * Make changes known to hardware.
1144 1.1 cgd */
1145 1.1 cgd dcm->dcm_data[port].dcm_baud = ospeed;
1146 1.1 cgd dcm->dcm_data[port].dcm_conf = mode;
1147 1.1 cgd SEM_LOCK(dcm);
1148 1.1 cgd dcm->dcm_cmdtab[port].dcm_data |= CT_CON;
1149 1.1 cgd dcm->dcm_cr |= (1 << port);
1150 1.1 cgd SEM_UNLOCK(dcm);
1151 1.1 cgd /*
1152 1.1 cgd * Delay for config change to take place. Weighted by baud.
1153 1.1 cgd * XXX why do we do this?
1154 1.1 cgd */
1155 1.1 cgd DELAY(16 * DCM_USPERCH(tp->t_ospeed));
1156 1.72 tsutsui return 0;
1157 1.1 cgd }
1158 1.63 tsutsui
1159 1.65 thorpej static void
1160 1.65 thorpej dcmstart(struct tty *tp)
1161 1.1 cgd {
1162 1.20 thorpej struct dcm_softc *sc;
1163 1.20 thorpej struct dcmdevice *dcm;
1164 1.20 thorpej struct dcmpreg *pp;
1165 1.20 thorpej struct dcmtfifo *fifo;
1166 1.20 thorpej char *bp;
1167 1.20 thorpej u_int head, tail, next;
1168 1.20 thorpej int unit, board, port, nch;
1169 1.1 cgd char buf[16];
1170 1.1 cgd int s;
1171 1.14 mycroft #ifdef DCMSTATS
1172 1.20 thorpej struct dcmstats *dsp = &sc->sc_stats;
1173 1.1 cgd int tch = 0;
1174 1.1 cgd #endif
1175 1.1 cgd
1176 1.20 thorpej unit = DCMUNIT(tp->t_dev);
1177 1.20 thorpej board = DCMBOARD(unit);
1178 1.20 thorpej port = DCMPORT(unit);
1179 1.20 thorpej
1180 1.81 cegger sc = device_lookup_private(&dcm_cd, board);
1181 1.20 thorpej dcm = sc->sc_dcm;
1182 1.20 thorpej
1183 1.1 cgd s = spltty();
1184 1.14 mycroft #ifdef DCMSTATS
1185 1.1 cgd dsp->xints++;
1186 1.1 cgd #endif
1187 1.1 cgd #ifdef DEBUG
1188 1.1 cgd if (dcmdebug & DDB_OUTPUT)
1189 1.31 christos printf("%s port %d: dcmstart: state %x flags %x outcc %d\n",
1190 1.79 tsutsui device_xname(sc->sc_dev), port, tp->t_state, tp->t_flags,
1191 1.79 tsutsui tp->t_outq.c_cc);
1192 1.1 cgd #endif
1193 1.1 cgd if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
1194 1.1 cgd goto out;
1195 1.78 ad if (!ttypull(tp)) {
1196 1.14 mycroft #ifdef DCMSTATS
1197 1.1 cgd dsp->xempty++;
1198 1.1 cgd #endif
1199 1.1 cgd goto out;
1200 1.1 cgd }
1201 1.1 cgd
1202 1.1 cgd pp = dcm_preg(dcm, port);
1203 1.1 cgd tail = pp->t_tail & TX_MASK;
1204 1.1 cgd next = (tail + 1) & TX_MASK;
1205 1.1 cgd head = pp->t_head & TX_MASK;
1206 1.1 cgd if (head == next)
1207 1.1 cgd goto out;
1208 1.1 cgd fifo = &dcm->dcm_tfifos[3-port][tail];
1209 1.1 cgd again:
1210 1.1 cgd nch = q_to_b(&tp->t_outq, buf, (head - next) & TX_MASK);
1211 1.14 mycroft #ifdef DCMSTATS
1212 1.1 cgd tch += nch;
1213 1.1 cgd #endif
1214 1.1 cgd #ifdef DEBUG
1215 1.1 cgd if (dcmdebug & DDB_OUTPUT)
1216 1.31 christos printf("\thead %x tail %x nch %d\n", head, tail, nch);
1217 1.1 cgd #endif
1218 1.1 cgd /*
1219 1.1 cgd * Loop transmitting all the characters we can.
1220 1.1 cgd */
1221 1.1 cgd for (bp = buf; --nch >= 0; bp++) {
1222 1.1 cgd fifo->data_char = *bp;
1223 1.1 cgd pp->t_tail = next;
1224 1.1 cgd /*
1225 1.1 cgd * If this is the first character,
1226 1.1 cgd * get the hardware moving right now.
1227 1.1 cgd */
1228 1.1 cgd if (bp == buf) {
1229 1.1 cgd tp->t_state |= TS_BUSY;
1230 1.1 cgd SEM_LOCK(dcm);
1231 1.1 cgd dcm->dcm_cmdtab[port].dcm_data |= CT_TX;
1232 1.1 cgd dcm->dcm_cr |= (1 << port);
1233 1.1 cgd SEM_UNLOCK(dcm);
1234 1.1 cgd }
1235 1.1 cgd tail = next;
1236 1.1 cgd fifo = tail ? fifo+1 : &dcm->dcm_tfifos[3-port][0];
1237 1.1 cgd next = (next + 1) & TX_MASK;
1238 1.1 cgd }
1239 1.1 cgd /*
1240 1.1 cgd * Head changed while we were loading the buffer,
1241 1.1 cgd * go back and load some more if we can.
1242 1.1 cgd */
1243 1.7 mycroft if (tp->t_outq.c_cc && head != (pp->t_head & TX_MASK)) {
1244 1.14 mycroft #ifdef DCMSTATS
1245 1.1 cgd dsp->xrestarts++;
1246 1.1 cgd #endif
1247 1.1 cgd head = pp->t_head & TX_MASK;
1248 1.1 cgd goto again;
1249 1.1 cgd }
1250 1.1 cgd
1251 1.1 cgd /*
1252 1.1 cgd * Kick it one last time in case it finished while we were
1253 1.1 cgd * loading the last bunch.
1254 1.1 cgd */
1255 1.1 cgd if (bp > &buf[1]) {
1256 1.1 cgd tp->t_state |= TS_BUSY;
1257 1.1 cgd SEM_LOCK(dcm);
1258 1.1 cgd dcm->dcm_cmdtab[port].dcm_data |= CT_TX;
1259 1.1 cgd dcm->dcm_cr |= (1 << port);
1260 1.1 cgd SEM_UNLOCK(dcm);
1261 1.1 cgd }
1262 1.1 cgd #ifdef DEBUG
1263 1.1 cgd if (dcmdebug & DDB_INTR)
1264 1.37 scottr printf("%s port %d: dcmstart: head %x tail %x outqcc %d\n",
1265 1.79 tsutsui device_xname(sc->sc_dev), port, head, tail,
1266 1.79 tsutsui tp->t_outq.c_cc);
1267 1.1 cgd #endif
1268 1.1 cgd out:
1269 1.14 mycroft #ifdef DCMSTATS
1270 1.1 cgd dsp->xchars += tch;
1271 1.1 cgd if (tch <= DCMXBSIZE)
1272 1.1 cgd dsp->xsilo[tch]++;
1273 1.1 cgd else
1274 1.1 cgd dsp->xsilo[DCMXBSIZE+1]++;
1275 1.1 cgd #endif
1276 1.1 cgd splx(s);
1277 1.1 cgd }
1278 1.63 tsutsui
1279 1.1 cgd /*
1280 1.1 cgd * Stop output on a line.
1281 1.1 cgd */
1282 1.65 thorpej static void
1283 1.65 thorpej dcmstop(struct tty *tp, int flag)
1284 1.1 cgd {
1285 1.1 cgd int s;
1286 1.1 cgd
1287 1.1 cgd s = spltty();
1288 1.1 cgd if (tp->t_state & TS_BUSY) {
1289 1.1 cgd /* XXX is there some way to safely stop transmission? */
1290 1.1 cgd if ((tp->t_state&TS_TTSTOP) == 0)
1291 1.1 cgd tp->t_state |= TS_FLUSH;
1292 1.1 cgd }
1293 1.1 cgd splx(s);
1294 1.1 cgd }
1295 1.63 tsutsui
1296 1.1 cgd /*
1297 1.1 cgd * Modem control
1298 1.1 cgd */
1299 1.36 scottr int
1300 1.65 thorpej dcmmctl(dev_t dev, int bits, int how)
1301 1.1 cgd {
1302 1.20 thorpej struct dcm_softc *sc;
1303 1.20 thorpej struct dcmdevice *dcm;
1304 1.20 thorpej int s, unit, brd, port, hit = 0;
1305 1.20 thorpej
1306 1.20 thorpej unit = DCMUNIT(dev);
1307 1.20 thorpej brd = DCMBOARD(unit);
1308 1.20 thorpej port = DCMPORT(unit);
1309 1.34 thorpej
1310 1.81 cegger sc = device_lookup_private(&dcm_cd, brd);
1311 1.20 thorpej dcm = sc->sc_dcm;
1312 1.1 cgd
1313 1.1 cgd #ifdef DEBUG
1314 1.1 cgd if (dcmdebug & DDB_MODEM)
1315 1.31 christos printf("%s port %d: dcmmctl: bits 0x%x how %x\n",
1316 1.79 tsutsui device_xname(sc->sc_dev), port, bits, how);
1317 1.1 cgd #endif
1318 1.1 cgd
1319 1.1 cgd s = spltty();
1320 1.20 thorpej
1321 1.1 cgd switch (how) {
1322 1.1 cgd case DMSET:
1323 1.20 thorpej sc->sc_modem[port]->mdmout = bits;
1324 1.1 cgd hit++;
1325 1.1 cgd break;
1326 1.1 cgd
1327 1.1 cgd case DMBIS:
1328 1.20 thorpej sc->sc_modem[port]->mdmout |= bits;
1329 1.1 cgd hit++;
1330 1.1 cgd break;
1331 1.1 cgd
1332 1.1 cgd case DMBIC:
1333 1.20 thorpej sc->sc_modem[port]->mdmout &= ~bits;
1334 1.1 cgd hit++;
1335 1.1 cgd break;
1336 1.1 cgd
1337 1.1 cgd case DMGET:
1338 1.20 thorpej bits = sc->sc_modem[port]->mdmin;
1339 1.20 thorpej if (sc->sc_flags & DCM_STDDCE)
1340 1.1 cgd bits = hp2dce_in(bits);
1341 1.1 cgd break;
1342 1.1 cgd }
1343 1.1 cgd if (hit) {
1344 1.1 cgd SEM_LOCK(dcm);
1345 1.1 cgd dcm->dcm_modemchng |= 1<<(unit & 3);
1346 1.1 cgd dcm->dcm_cr |= CR_MODM;
1347 1.1 cgd SEM_UNLOCK(dcm);
1348 1.1 cgd DELAY(10); /* delay until done */
1349 1.49 gmcgarry splx(s);
1350 1.1 cgd }
1351 1.72 tsutsui return bits;
1352 1.1 cgd }
1353 1.1 cgd
1354 1.1 cgd /*
1355 1.1 cgd * Set board to either interrupt per-character or at a fixed interval.
1356 1.1 cgd */
1357 1.65 thorpej static void
1358 1.65 thorpej dcmsetischeme(int brd, int flags)
1359 1.1 cgd {
1360 1.81 cegger struct dcm_softc *sc = device_lookup_private(&dcm_cd, brd);
1361 1.20 thorpej struct dcmdevice *dcm = sc->sc_dcm;
1362 1.20 thorpej struct dcmischeme *dis = &sc->sc_scheme;
1363 1.20 thorpej int i;
1364 1.1 cgd u_char mask;
1365 1.1 cgd int perchar = flags & DIS_PERCHAR;
1366 1.1 cgd
1367 1.1 cgd #ifdef DEBUG
1368 1.1 cgd if (dcmdebug & DDB_INTSCHM)
1369 1.31 christos printf("%s: dcmsetischeme(%d): cur %d, ints %d, chars %d\n",
1370 1.79 tsutsui device_xname(sc->sc_dev), perchar, dis->dis_perchar,
1371 1.79 tsutsui dis->dis_intr, dis->dis_char);
1372 1.1 cgd if ((flags & DIS_RESET) == 0 && perchar == dis->dis_perchar) {
1373 1.31 christos printf("%s: dcmsetischeme: redundent request %d\n",
1374 1.79 tsutsui device_xname(sc->sc_dev), perchar);
1375 1.1 cgd return;
1376 1.1 cgd }
1377 1.1 cgd #endif
1378 1.1 cgd /*
1379 1.1 cgd * If perchar is non-zero, we enable interrupts on all characters
1380 1.1 cgd * otherwise we disable perchar interrupts and use periodic
1381 1.1 cgd * polling interrupts.
1382 1.1 cgd */
1383 1.1 cgd dis->dis_perchar = perchar;
1384 1.1 cgd mask = perchar ? 0xf : 0x0;
1385 1.1 cgd for (i = 0; i < 256; i++)
1386 1.1 cgd dcm->dcm_bmap[i].data_data = mask;
1387 1.1 cgd /*
1388 1.1 cgd * Don't slow down tandem mode, interrupt on flow control
1389 1.1 cgd * chars for any port on the board.
1390 1.1 cgd */
1391 1.1 cgd if (!perchar) {
1392 1.36 scottr struct tty *tp;
1393 1.1 cgd int c;
1394 1.1 cgd
1395 1.20 thorpej for (i = 0; i < NDCMPORT; i++) {
1396 1.20 thorpej tp = sc->sc_tty[i];
1397 1.20 thorpej
1398 1.86 dholland c = tty_getctrlchar(tp, VSTART);
1399 1.86 dholland if (c != _POSIX_VDISABLE)
1400 1.1 cgd dcm->dcm_bmap[c].data_data |= (1 << i);
1401 1.86 dholland c = tty_getctrlchar(tp, VSTOP);
1402 1.86 dholland if (c != _POSIX_VDISABLE)
1403 1.1 cgd dcm->dcm_bmap[c].data_data |= (1 << i);
1404 1.1 cgd }
1405 1.1 cgd }
1406 1.1 cgd /*
1407 1.1 cgd * Board starts with timer disabled so if first call is to
1408 1.1 cgd * set perchar mode then we don't want to toggle the timer.
1409 1.1 cgd */
1410 1.1 cgd if (flags == (DIS_RESET|DIS_PERCHAR))
1411 1.1 cgd return;
1412 1.1 cgd /*
1413 1.1 cgd * Toggle card 16.7ms interrupts (we first make sure that card
1414 1.1 cgd * has cleared the bit so it will see the toggle).
1415 1.1 cgd */
1416 1.1 cgd while (dcm->dcm_cr & CR_TIMER)
1417 1.1 cgd ;
1418 1.1 cgd SEM_LOCK(dcm);
1419 1.1 cgd dcm->dcm_cr |= CR_TIMER;
1420 1.1 cgd SEM_UNLOCK(dcm);
1421 1.1 cgd }
1422 1.1 cgd
1423 1.65 thorpej static void
1424 1.65 thorpej dcminit(struct dcmdevice *dcm, int port, int rate)
1425 1.22 thorpej {
1426 1.22 thorpej int s, mode;
1427 1.22 thorpej
1428 1.22 thorpej mode = LC_8BITS | LC_1STOP;
1429 1.22 thorpej
1430 1.22 thorpej s = splhigh();
1431 1.22 thorpej
1432 1.22 thorpej /*
1433 1.22 thorpej * Wait for transmitter buffer to empty.
1434 1.22 thorpej */
1435 1.22 thorpej while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)
1436 1.22 thorpej DELAY(DCM_USPERCH(rate));
1437 1.22 thorpej
1438 1.22 thorpej /*
1439 1.22 thorpej * Make changes known to hardware.
1440 1.22 thorpej */
1441 1.22 thorpej dcm->dcm_data[port].dcm_baud = ttspeedtab(rate, dcmspeedtab);
1442 1.22 thorpej dcm->dcm_data[port].dcm_conf = mode;
1443 1.22 thorpej SEM_LOCK(dcm);
1444 1.22 thorpej dcm->dcm_cmdtab[port].dcm_data |= CT_CON;
1445 1.22 thorpej dcm->dcm_cr |= (1 << port);
1446 1.22 thorpej SEM_UNLOCK(dcm);
1447 1.22 thorpej
1448 1.22 thorpej /*
1449 1.22 thorpej * Delay for config change to take place. Weighted by baud.
1450 1.22 thorpej * XXX why do we do this?
1451 1.22 thorpej */
1452 1.22 thorpej DELAY(16 * DCM_USPERCH(rate));
1453 1.22 thorpej splx(s);
1454 1.22 thorpej }
1455 1.22 thorpej
1456 1.1 cgd /*
1457 1.34 thorpej * Empirically derived self-test magic
1458 1.34 thorpej */
1459 1.65 thorpej static int
1460 1.65 thorpej dcmselftest(struct dcm_softc *sc)
1461 1.34 thorpej {
1462 1.34 thorpej struct dcmdevice *dcm = sc->sc_dcm;
1463 1.36 scottr int timo = 0;
1464 1.36 scottr int s, rv;
1465 1.34 thorpej
1466 1.35 thorpej rv = 1;
1467 1.35 thorpej
1468 1.35 thorpej s = splhigh();
1469 1.34 thorpej dcm->dcm_rsid = DCMRS;
1470 1.34 thorpej DELAY(50000); /* 5000 is not long enough */
1471 1.63 tsutsui dcm->dcm_rsid = 0;
1472 1.34 thorpej dcm->dcm_ic = IC_IE;
1473 1.34 thorpej dcm->dcm_cr = CR_SELFT;
1474 1.35 thorpej while ((dcm->dcm_ic & IC_IR) == 0) {
1475 1.34 thorpej if (++timo == 20000)
1476 1.35 thorpej goto out;
1477 1.35 thorpej DELAY(1);
1478 1.35 thorpej }
1479 1.34 thorpej DELAY(50000); /* XXX why is this needed ???? */
1480 1.35 thorpej while ((dcm->dcm_iir & IIR_SELFT) == 0) {
1481 1.34 thorpej if (++timo == 400000)
1482 1.35 thorpej goto out;
1483 1.35 thorpej DELAY(1);
1484 1.35 thorpej }
1485 1.34 thorpej DELAY(50000); /* XXX why is this needed ???? */
1486 1.34 thorpej if (dcm->dcm_stcon != ST_OK) {
1487 1.34 thorpej #if 0
1488 1.34 thorpej if (hd->hp_args->hw_sc != conscode)
1489 1.79 tsutsui aprint_error_dev(sc->sc_dev, "self test failed: %x\n",
1490 1.79 tsutsui dcm->dcm_stcon);
1491 1.34 thorpej #endif
1492 1.35 thorpej goto out;
1493 1.34 thorpej }
1494 1.34 thorpej dcm->dcm_ic = IC_ID;
1495 1.35 thorpej rv = 0;
1496 1.35 thorpej
1497 1.35 thorpej out:
1498 1.34 thorpej splx(s);
1499 1.72 tsutsui return rv;
1500 1.34 thorpej }
1501 1.34 thorpej
1502 1.34 thorpej /*
1503 1.1 cgd * Following are all routines needed for DCM to act as console
1504 1.1 cgd */
1505 1.1 cgd
1506 1.24 thorpej int
1507 1.48 gmcgarry dcmcnattach(bus_space_tag_t bst, bus_addr_t addr, int scode)
1508 1.1 cgd {
1509 1.59 gmcgarry bus_space_handle_t bsh;
1510 1.77 christos void *va;
1511 1.59 gmcgarry struct dcmdevice *dcm;
1512 1.52 gehenna int maj;
1513 1.48 gmcgarry
1514 1.59 gmcgarry if (bus_space_map(bst, addr, DIOCSIZE, 0, &bsh))
1515 1.72 tsutsui return 1;
1516 1.48 gmcgarry
1517 1.59 gmcgarry va = bus_space_vaddr(bst, bsh);
1518 1.48 gmcgarry dcm = (struct dcmdevice *)va;
1519 1.1 cgd
1520 1.20 thorpej switch (dcm->dcm_rsid) {
1521 1.48 gmcgarry #ifdef CONSCODE
1522 1.1 cgd case DCMID:
1523 1.48 gmcgarry #endif
1524 1.1 cgd case DCMID|DCMCON:
1525 1.1 cgd break;
1526 1.1 cgd default:
1527 1.48 gmcgarry goto error;
1528 1.22 thorpej }
1529 1.24 thorpej
1530 1.48 gmcgarry dcminit(dcm, DCMCONSPORT, dcmdefaultrate);
1531 1.59 gmcgarry dcmconsinit = 1;
1532 1.48 gmcgarry dcmconscode = scode;
1533 1.59 gmcgarry dcm_cn = dcm;
1534 1.48 gmcgarry
1535 1.59 gmcgarry /* locate the major number */
1536 1.59 gmcgarry maj = cdevsw_lookup_major(&dcm_cdevsw);
1537 1.48 gmcgarry
1538 1.59 gmcgarry /* initialize required fields */
1539 1.59 gmcgarry cn_tab = &dcm_cons;
1540 1.59 gmcgarry cn_tab->cn_dev = makedev(maj, 0);
1541 1.22 thorpej
1542 1.1 cgd #ifdef KGDB_CHEAT
1543 1.24 thorpej /* XXX this needs to be fixed. */
1544 1.1 cgd /*
1545 1.1 cgd * This doesn't currently work, at least not with ite consoles;
1546 1.1 cgd * the console hasn't been initialized yet.
1547 1.1 cgd */
1548 1.52 gehenna if (major(kgdb_dev) == maj &&
1549 1.20 thorpej DCMBOARD(DCMUNIT(kgdb_dev)) == DCMBOARD(unit)) {
1550 1.22 thorpej dcminit(dcm_cn, DCMPORT(DCMUNIT(kgdb_dev)), kgdb_rate);
1551 1.1 cgd if (kgdb_debug_init) {
1552 1.1 cgd /*
1553 1.1 cgd * We assume that console is ready for us...
1554 1.1 cgd * this assumes that a dca or ite console
1555 1.1 cgd * has been selected already and will init
1556 1.1 cgd * on the first putc.
1557 1.1 cgd */
1558 1.31 christos printf("dcm%d: ", DCMUNIT(kgdb_dev));
1559 1.1 cgd kgdb_connect(1);
1560 1.1 cgd }
1561 1.1 cgd }
1562 1.1 cgd #endif
1563 1.1 cgd
1564 1.20 thorpej
1565 1.72 tsutsui return 0;
1566 1.48 gmcgarry
1567 1.48 gmcgarry error:
1568 1.59 gmcgarry bus_space_unmap(bst, bsh, DIOCSIZE);
1569 1.72 tsutsui return 1;
1570 1.1 cgd }
1571 1.1 cgd
1572 1.24 thorpej /* ARGSUSED */
1573 1.65 thorpej static int
1574 1.65 thorpej dcmcngetc(dev_t dev)
1575 1.1 cgd {
1576 1.20 thorpej struct dcmrfifo *fifo;
1577 1.20 thorpej struct dcmpreg *pp;
1578 1.20 thorpej u_int head;
1579 1.24 thorpej int s, c, stat;
1580 1.22 thorpej
1581 1.24 thorpej pp = dcm_preg(dcm_cn, DCMCONSPORT);
1582 1.20 thorpej
1583 1.1 cgd s = splhigh();
1584 1.1 cgd head = pp->r_head & RX_MASK;
1585 1.24 thorpej fifo = &dcm_cn->dcm_rfifos[3-DCMCONSPORT][head>>1];
1586 1.1 cgd while (head == (pp->r_tail & RX_MASK))
1587 1.1 cgd ;
1588 1.1 cgd /*
1589 1.1 cgd * If board interrupts are enabled, just let our received char
1590 1.1 cgd * interrupt through in case some other port on the board was
1591 1.1 cgd * busy. Otherwise we must clear the interrupt.
1592 1.1 cgd */
1593 1.22 thorpej SEM_LOCK(dcm_cn);
1594 1.22 thorpej if ((dcm_cn->dcm_ic & IC_IE) == 0)
1595 1.22 thorpej stat = dcm_cn->dcm_iir;
1596 1.22 thorpej SEM_UNLOCK(dcm_cn);
1597 1.1 cgd c = fifo->data_char;
1598 1.1 cgd stat = fifo->data_stat;
1599 1.1 cgd pp->r_head = (head + 2) & RX_MASK;
1600 1.85 christos __USE(stat);
1601 1.1 cgd splx(s);
1602 1.72 tsutsui return c;
1603 1.1 cgd }
1604 1.1 cgd
1605 1.1 cgd /*
1606 1.1 cgd * Console kernel output character routine.
1607 1.1 cgd */
1608 1.24 thorpej /* ARGSUSED */
1609 1.65 thorpej static void
1610 1.65 thorpej dcmcnputc(dev_t dev, int c)
1611 1.1 cgd {
1612 1.20 thorpej struct dcmpreg *pp;
1613 1.1 cgd unsigned tail;
1614 1.36 scottr int s, stat;
1615 1.22 thorpej
1616 1.24 thorpej pp = dcm_preg(dcm_cn, DCMCONSPORT);
1617 1.20 thorpej
1618 1.1 cgd s = splhigh();
1619 1.1 cgd #ifdef KGDB
1620 1.1 cgd if (dev != kgdb_dev)
1621 1.1 cgd #endif
1622 1.1 cgd if (dcmconsinit == 0) {
1623 1.24 thorpej dcminit(dcm_cn, DCMCONSPORT, dcmdefaultrate);
1624 1.1 cgd dcmconsinit = 1;
1625 1.1 cgd }
1626 1.1 cgd tail = pp->t_tail & TX_MASK;
1627 1.1 cgd while (tail != (pp->t_head & TX_MASK))
1628 1.85 christos continue;
1629 1.24 thorpej dcm_cn->dcm_tfifos[3-DCMCONSPORT][tail].data_char = c;
1630 1.1 cgd pp->t_tail = tail = (tail + 1) & TX_MASK;
1631 1.22 thorpej SEM_LOCK(dcm_cn);
1632 1.24 thorpej dcm_cn->dcm_cmdtab[DCMCONSPORT].dcm_data |= CT_TX;
1633 1.24 thorpej dcm_cn->dcm_cr |= (1 << DCMCONSPORT);
1634 1.22 thorpej SEM_UNLOCK(dcm_cn);
1635 1.1 cgd while (tail != (pp->t_head & TX_MASK))
1636 1.85 christos continue;
1637 1.1 cgd /*
1638 1.1 cgd * If board interrupts are enabled, just let our completion
1639 1.1 cgd * interrupt through in case some other port on the board
1640 1.1 cgd * was busy. Otherwise we must clear the interrupt.
1641 1.1 cgd */
1642 1.22 thorpej if ((dcm_cn->dcm_ic & IC_IE) == 0) {
1643 1.22 thorpej SEM_LOCK(dcm_cn);
1644 1.22 thorpej stat = dcm_cn->dcm_iir;
1645 1.22 thorpej SEM_UNLOCK(dcm_cn);
1646 1.1 cgd }
1647 1.85 christos __USE(stat);
1648 1.1 cgd splx(s);
1649 1.1 cgd }
1650