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