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