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