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