1 1.32 thorpej /* $NetBSD: sbjcn.c,v 1.32 2021/01/04 18:19:53 thorpej Exp $ */ 2 1.1 simonb 3 1.1 simonb /* 4 1.1 simonb * Copyright 2000, 2001 5 1.1 simonb * Broadcom Corporation. All rights reserved. 6 1.1 simonb * 7 1.1 simonb * This software is furnished under license and may be used and copied only 8 1.1 simonb * in accordance with the following terms and conditions. Subject to these 9 1.1 simonb * conditions, you may download, copy, install, use, modify and distribute 10 1.1 simonb * modified or unmodified copies of this software in source and/or binary 11 1.1 simonb * form. No title or ownership is transferred hereby. 12 1.1 simonb * 13 1.1 simonb * 1) Any source code used, modified or distributed must reproduce and 14 1.1 simonb * retain this copyright notice and list of conditions as they appear in 15 1.1 simonb * the source file. 16 1.1 simonb * 17 1.1 simonb * 2) No right is granted to use any trade name, trademark, or logo of 18 1.6 cgd * Broadcom Corporation. The "Broadcom Corporation" name may not be 19 1.6 cgd * used to endorse or promote products derived from this software 20 1.6 cgd * without the prior written permission of Broadcom Corporation. 21 1.1 simonb * 22 1.1 simonb * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR IMPLIED 23 1.1 simonb * WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OF 24 1.1 simonb * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR 25 1.1 simonb * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM BE LIABLE 26 1.1 simonb * FOR ANY DAMAGES WHATSOEVER, AND IN PARTICULAR, BROADCOM SHALL NOT BE 27 1.1 simonb * LIABLE FOR DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 1.1 simonb * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 1.1 simonb * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 30 1.1 simonb * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 31 1.1 simonb * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 32 1.1 simonb * OR OTHERWISE), EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 1.1 simonb */ 34 1.1 simonb 35 1.1 simonb /* from: $NetBSD: com.c,v 1.172 2000/05/03 19:19:04 thorpej Exp */ 36 1.1 simonb 37 1.1 simonb /*- 38 1.1 simonb * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. 39 1.1 simonb * All rights reserved. 40 1.1 simonb * 41 1.1 simonb * This code is derived from software contributed to The NetBSD Foundation 42 1.1 simonb * by Charles M. Hannum. 43 1.1 simonb * 44 1.1 simonb * Redistribution and use in source and binary forms, with or without 45 1.1 simonb * modification, are permitted provided that the following conditions 46 1.1 simonb * are met: 47 1.1 simonb * 1. Redistributions of source code must retain the above copyright 48 1.1 simonb * notice, this list of conditions and the following disclaimer. 49 1.1 simonb * 2. Redistributions in binary form must reproduce the above copyright 50 1.1 simonb * notice, this list of conditions and the following disclaimer in the 51 1.1 simonb * documentation and/or other materials provided with the distribution. 52 1.1 simonb * 53 1.1 simonb * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 54 1.1 simonb * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 55 1.1 simonb * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 56 1.1 simonb * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 57 1.1 simonb * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 58 1.1 simonb * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 59 1.1 simonb * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 60 1.1 simonb * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 61 1.1 simonb * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 62 1.1 simonb * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 63 1.1 simonb * POSSIBILITY OF SUCH DAMAGE. 64 1.1 simonb */ 65 1.1 simonb 66 1.1 simonb /* 67 1.1 simonb * Copyright (c) 1991 The Regents of the University of California. 68 1.1 simonb * All rights reserved. 69 1.1 simonb * 70 1.1 simonb * Redistribution and use in source and binary forms, with or without 71 1.1 simonb * modification, are permitted provided that the following conditions 72 1.1 simonb * are met: 73 1.1 simonb * 1. Redistributions of source code must retain the above copyright 74 1.1 simonb * notice, this list of conditions and the following disclaimer. 75 1.1 simonb * 2. Redistributions in binary form must reproduce the above copyright 76 1.1 simonb * notice, this list of conditions and the following disclaimer in the 77 1.1 simonb * documentation and/or other materials provided with the distribution. 78 1.8 agc * 3. Neither the name of the University nor the names of its contributors 79 1.1 simonb * may be used to endorse or promote products derived from this software 80 1.1 simonb * without specific prior written permission. 81 1.1 simonb * 82 1.1 simonb * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 83 1.1 simonb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 84 1.1 simonb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 85 1.1 simonb * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 86 1.1 simonb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 87 1.1 simonb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 88 1.1 simonb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 89 1.1 simonb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 90 1.1 simonb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 91 1.1 simonb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 92 1.1 simonb * SUCH DAMAGE. 93 1.1 simonb * 94 1.1 simonb * @(#)com.c 7.5 (Berkeley) 5/16/91 95 1.1 simonb */ 96 1.1 simonb 97 1.1 simonb /* 98 1.1 simonb * `sbjcn' driver, supports console over SiByte SB-1250 JTAG. 99 1.1 simonb * 100 1.1 simonb * Accesses a section of JTAG memory space to mimic a console, 101 1.1 simonb * if there's a matching program outside to communicate with. 102 1.1 simonb * If nobody is there, things will be very quiet. 103 1.1 simonb */ 104 1.7 lukem 105 1.7 lukem #include <sys/cdefs.h> 106 1.32 thorpej __KERNEL_RCSID(0, "$NetBSD: sbjcn.c,v 1.32 2021/01/04 18:19:53 thorpej Exp $"); 107 1.7 lukem 108 1.7 lukem #define SBJCN_DEBUG 109 1.1 simonb 110 1.1 simonb #include "opt_ddb.h" 111 1.25 matt #include "ioconf.h" 112 1.1 simonb 113 1.1 simonb #include <sys/param.h> 114 1.1 simonb #include <sys/systm.h> 115 1.1 simonb #include <sys/ioctl.h> 116 1.1 simonb #include <sys/select.h> 117 1.1 simonb #include <sys/tty.h> 118 1.1 simonb #include <sys/proc.h> 119 1.1 simonb #include <sys/conf.h> 120 1.1 simonb #include <sys/file.h> 121 1.1 simonb #include <sys/uio.h> 122 1.1 simonb #include <sys/kernel.h> 123 1.1 simonb #include <sys/syslog.h> 124 1.1 simonb #include <sys/types.h> 125 1.1 simonb #include <sys/device.h> 126 1.32 thorpej #include <sys/kmem.h> 127 1.1 simonb #include <sys/vnode.h> 128 1.12 elad #include <sys/kauth.h> 129 1.1 simonb 130 1.1 simonb #include <sbmips/dev/sbscd/sbscdvar.h> 131 1.1 simonb #include <sbmips/dev/sbscd/sbjcnvar.h> 132 1.28 matt 133 1.1 simonb #include <dev/cons.h> 134 1.28 matt 135 1.28 matt #include <mips/locore.h> 136 1.1 simonb 137 1.1 simonb void sbjcn_attach_channel(struct sbjcn_softc *sc, int chan, int intr); 138 1.1 simonb static void sbjcncn_grabdword(struct sbjcn_channel *ch); 139 1.1 simonb static char sbjcncn_nextbyte(struct sbjcn_channel *ch); 140 1.1 simonb static void sbjcn_cngrabdword(void); 141 1.1 simonb 142 1.1 simonb #if defined(DDB) || defined(KGDB) 143 1.1 simonb static void sbjcn_enable_debugport(struct sbjcn_channel *ch); 144 1.1 simonb #endif 145 1.1 simonb void sbjcn_config(struct sbjcn_channel *ch); 146 1.1 simonb void sbjcn_shutdown(struct sbjcn_channel *ch); 147 1.1 simonb int sbjcn_speed(long, long *); 148 1.1 simonb static int cflag2modes(tcflag_t, u_char *, u_char *); 149 1.1 simonb int sbjcn_param(struct tty *, struct termios *); 150 1.1 simonb void sbjcn_start(struct tty *); 151 1.1 simonb int sbjcn_hwiflow(struct tty *, int); 152 1.1 simonb 153 1.1 simonb void sbjcn_loadchannelregs(struct sbjcn_channel *); 154 1.1 simonb void sbjcn_dohwiflow(struct sbjcn_channel *); 155 1.1 simonb void sbjcn_break(struct sbjcn_channel *, int); 156 1.1 simonb void sbjcn_modem(struct sbjcn_channel *, int); 157 1.1 simonb void tiocm_to_sbjcn(struct sbjcn_channel *, int, int); 158 1.1 simonb int sbjcn_to_tiocm(struct sbjcn_channel *); 159 1.1 simonb void sbjcn_iflush(struct sbjcn_channel *); 160 1.1 simonb 161 1.1 simonb int sbjcn_init(u_long addr, int chan, int rate, tcflag_t cflag); 162 1.1 simonb int sbjcn_common_getc(u_long addr, int chan); 163 1.1 simonb void sbjcn_common_putc(u_long addr, int chan, int c); 164 1.1 simonb 165 1.1 simonb int sbjcn_cngetc(dev_t dev); 166 1.1 simonb void sbjcn_cnputc(dev_t dev, int c); 167 1.1 simonb void sbjcn_cnpollc(dev_t dev, int on); 168 1.1 simonb 169 1.2 gehenna dev_type_open(sbjcnopen); 170 1.2 gehenna dev_type_close(sbjcnclose); 171 1.2 gehenna dev_type_read(sbjcnread); 172 1.2 gehenna dev_type_write(sbjcnwrite); 173 1.2 gehenna dev_type_ioctl(sbjcnioctl); 174 1.2 gehenna dev_type_stop(sbjcnstop); 175 1.2 gehenna dev_type_tty(sbjcntty); 176 1.2 gehenna 177 1.2 gehenna const struct cdevsw sbjcn_cdevsw = { 178 1.29 dholland .d_open = sbjcnopen, 179 1.29 dholland .d_close = sbjcnclose, 180 1.29 dholland .d_read = sbjcnread, 181 1.29 dholland .d_write = sbjcnwrite, 182 1.29 dholland .d_ioctl = sbjcnioctl, 183 1.29 dholland .d_stop = sbjcnstop, 184 1.29 dholland .d_tty = sbjcntty, 185 1.29 dholland .d_poll = nopoll, 186 1.29 dholland .d_mmap = nommap, 187 1.29 dholland .d_kqfilter = ttykqfilter, 188 1.30 dholland .d_discard = nodiscard, 189 1.29 dholland .d_flag = D_TTY 190 1.2 gehenna }; 191 1.2 gehenna 192 1.1 simonb #define integrate static inline 193 1.1 simonb integrate void sbjcn_rxsoft(struct sbjcn_channel *, struct tty *); 194 1.1 simonb integrate void sbjcn_txsoft(struct sbjcn_channel *, struct tty *); 195 1.1 simonb integrate void sbjcn_stsoft(struct sbjcn_channel *, struct tty *); 196 1.1 simonb integrate void sbjcn_schedrx(struct sbjcn_channel *); 197 1.1 simonb integrate void sbjcn_recv(struct sbjcn_channel *ch); 198 1.1 simonb void sbjcn_diag(void *); 199 1.1 simonb void sbjcn_callout(void *); 200 1.1 simonb 201 1.1 simonb /* 202 1.1 simonb * Make this an option variable one can patch. 203 1.1 simonb * But be warned: this must be a power of 2! 204 1.1 simonb */ 205 1.1 simonb u_int sbjcn_rbuf_size = SBJCN_RING_SIZE; 206 1.1 simonb 207 1.1 simonb /* Stop input when 3/4 of the ring is full; restart when only 1/4 is full. */ 208 1.1 simonb u_int sbjcn_rbuf_hiwat = (SBJCN_RING_SIZE * 1) / 4; 209 1.1 simonb u_int sbjcn_rbuf_lowat = (SBJCN_RING_SIZE * 3) / 4; 210 1.1 simonb 211 1.1 simonb static int sbjcn_cons_present; 212 1.1 simonb static int sbjcn_cons_attached; 213 1.1 simonb static u_long sbjcn_cons_addr; 214 1.1 simonb static int sbjcn_cons_chan; 215 1.1 simonb static int sbjcn_cons_rate; 216 1.1 simonb static tcflag_t sbjcn_cons_cflag; 217 1.1 simonb static int sbjcn_cons_waiting_input; 218 1.1 simonb static uint64_t sbjcn_cons_input_buf; 219 1.1 simonb 220 1.1 simonb #ifdef KGDB 221 1.1 simonb #include <sys/kgdb.h> 222 1.1 simonb 223 1.1 simonb static int sbjcn_kgdb_present; 224 1.1 simonb static int sbjcn_kgdb_attached; 225 1.1 simonb static u_long sbjcn_kgdb_addr; 226 1.1 simonb static int sbjcn_kgdb_chan; 227 1.1 simonb 228 1.1 simonb int sbjcn_kgdb_getc(void *); 229 1.1 simonb void sbjcn_kgdb_putc(void *, int); 230 1.1 simonb #endif /* KGDB */ 231 1.1 simonb 232 1.25 matt static int sbjcn_match(device_t, cfdata_t, void *); 233 1.25 matt static void sbjcn_attach(device_t, device_t, void *); 234 1.1 simonb 235 1.25 matt CFATTACH_DECL_NEW(sbjcn, sizeof(struct sbjcn_softc), 236 1.4 thorpej sbjcn_match, sbjcn_attach, NULL, NULL); 237 1.1 simonb 238 1.24 matt #define READ_REG(rp) (mips3_ld((volatile uint64_t *)(rp))) 239 1.24 matt #define WRITE_REG(rp, val) (mips3_sd((volatile uint64_t *)(rp), (val))) 240 1.1 simonb 241 1.1 simonb #define JTAG_CONS_CONTROL 0x00 242 1.1 simonb #define JTAG_CONS_INPUT 0x20 243 1.1 simonb #define JTAG_CONS_OUTPUT 0x40 244 1.1 simonb #define JTAG_CONS_MAGICNUM 0x50FABEEF12349873 245 1.1 simonb 246 1.1 simonb #define jtag_input_len(data) (((data) >> 56) & 0xFF) 247 1.1 simonb 248 1.1 simonb 249 1.1 simonb static int 250 1.25 matt sbjcn_match(device_t parent, cfdata_t match, void *aux) 251 1.1 simonb { 252 1.26 matt struct sbscd_attach_args *sa = aux; 253 1.1 simonb 254 1.26 matt if (sa->sa_locs.sa_type != SBSCD_DEVTYPE_JTAGCONS) 255 1.1 simonb return (0); 256 1.1 simonb 257 1.1 simonb return 1; 258 1.1 simonb } 259 1.1 simonb 260 1.1 simonb static void 261 1.25 matt sbjcn_attach(device_t parent, device_t self, void *aux) 262 1.1 simonb { 263 1.25 matt struct sbjcn_softc *sc = device_private(self); 264 1.26 matt struct sbscd_attach_args *sa = aux; 265 1.1 simonb 266 1.25 matt sc->sc_dev = self; 267 1.26 matt sc->sc_addr = sa->sa_base + sa->sa_locs.sa_offset; 268 1.1 simonb 269 1.26 matt aprint_normal("\n"); 270 1.26 matt sbjcn_attach_channel(sc, 0, sa->sa_locs.sa_intr[0]); 271 1.1 simonb } 272 1.1 simonb 273 1.1 simonb void 274 1.1 simonb sbjcn_attach_channel(struct sbjcn_softc *sc, int chan, int intr) 275 1.1 simonb { 276 1.1 simonb struct sbjcn_channel *ch = &sc->sc_channels[chan]; 277 1.1 simonb u_long chan_addr; 278 1.1 simonb struct tty *tp; 279 1.1 simonb 280 1.1 simonb ch->ch_sc = sc; 281 1.1 simonb ch->ch_num = chan; 282 1.1 simonb 283 1.1 simonb chan_addr = sc->sc_addr + (0x100 * chan); 284 1.1 simonb ch->ch_base = (void *)MIPS_PHYS_TO_KSEG1(chan_addr); 285 1.1 simonb ch->ch_input_reg = 286 1.1 simonb (void *)MIPS_PHYS_TO_KSEG1(sc->sc_addr + JTAG_CONS_INPUT); 287 1.1 simonb ch->ch_output_reg = 288 1.1 simonb (void *)MIPS_PHYS_TO_KSEG1(sc->sc_addr + JTAG_CONS_OUTPUT); 289 1.1 simonb ch->ch_control_reg = 290 1.1 simonb (void *)MIPS_PHYS_TO_KSEG1(sc->sc_addr + JTAG_CONS_CONTROL); 291 1.1 simonb ch->ch_waiting_input = 0; 292 1.1 simonb 293 1.1 simonb ch->ch_i_dcd = ch->ch_i_dcd_pin = 0 /* XXXCGD */; 294 1.1 simonb ch->ch_i_cts = ch->ch_i_cts_pin = 0 /* XXXCGD */; 295 1.1 simonb ch->ch_i_dsr = ch->ch_i_dsr_pin = 0 /* XXXCGD */; 296 1.1 simonb ch->ch_i_ri = ch->ch_i_ri_pin = 0 /* XXXCGD */; 297 1.1 simonb ch->ch_i_mask = 298 1.1 simonb ch->ch_i_dcd | ch->ch_i_cts | ch->ch_i_dsr | ch->ch_i_ri; 299 1.1 simonb ch->ch_o_dtr = ch->ch_o_dtr_pin = 0 /* XXXCGD */; 300 1.1 simonb ch->ch_o_rts = ch->ch_o_rts_pin = 0 /* XXXCGD */; 301 1.1 simonb ch->ch_o_mask = ch->ch_o_dtr | ch->ch_o_rts; 302 1.1 simonb 303 1.17 he callout_init(&ch->ch_diag_callout, 0); 304 1.17 he callout_init(&ch->ch_callout, 0); 305 1.1 simonb 306 1.1 simonb /* Disable interrupts before configuring the device. */ 307 1.1 simonb ch->ch_imr = 0; 308 1.1 simonb 309 1.1 simonb if (sbjcn_cons_present && 310 1.1 simonb sbjcn_cons_addr == chan_addr && sbjcn_cons_chan == chan) { 311 1.1 simonb sbjcn_cons_attached = 1; 312 1.1 simonb 313 1.1 simonb /* Make sure the console is always "hardwired". */ 314 1.1 simonb delay(1000); /* wait for output to finish */ 315 1.1 simonb SET(ch->ch_hwflags, SBJCN_HW_CONSOLE); 316 1.1 simonb SET(ch->ch_swflags, TIOCFLAG_SOFTCAR); 317 1.1 simonb } 318 1.1 simonb 319 1.27 rmind tp = tty_alloc(); 320 1.1 simonb tp->t_oproc = sbjcn_start; 321 1.1 simonb tp->t_param = sbjcn_param; 322 1.1 simonb tp->t_hwiflow = sbjcn_hwiflow; 323 1.1 simonb 324 1.1 simonb ch->ch_tty = tp; 325 1.32 thorpej ch->ch_rbuf = kmem_alloc(sbjcn_rbuf_size << 1, KM_SLEEP); 326 1.1 simonb ch->ch_ebuf = ch->ch_rbuf + (sbjcn_rbuf_size << 1); 327 1.1 simonb 328 1.1 simonb tty_attach(tp); 329 1.1 simonb 330 1.1 simonb if (ISSET(ch->ch_hwflags, SBJCN_HW_CONSOLE)) { 331 1.1 simonb int maj; 332 1.1 simonb 333 1.1 simonb /* locate the major number */ 334 1.2 gehenna maj = cdevsw_lookup_major(&sbjcn_cdevsw); 335 1.1 simonb 336 1.11 thorpej cn_tab->cn_dev = makedev(maj, 337 1.26 matt (device_unit(sc->sc_dev) << 1) + chan); 338 1.1 simonb 339 1.26 matt aprint_normal_dev(sc->sc_dev, "channel %d: %s\n", 340 1.26 matt chan, "console"); 341 1.1 simonb } 342 1.1 simonb 343 1.1 simonb #ifdef KGDB 344 1.1 simonb /* 345 1.1 simonb * Allow kgdb to "take over" this port. If this is 346 1.1 simonb * the kgdb device, it has exclusive use. 347 1.1 simonb */ 348 1.1 simonb if (sbjcn_kgdb_present && 349 1.1 simonb sbjcn_kgdb_addr == chan_addr && sbjcn_kgdb_chan == chan) { 350 1.1 simonb sbjcn_kgdb_attached = 1; 351 1.1 simonb 352 1.1 simonb SET(ch->ch_hwflags, SBJCN_HW_KGDB); 353 1.26 matt aprint_normal_dev(sc->sc_dev, "channel %d: %s\n", 354 1.26 matt chan, "kgdb"); 355 1.1 simonb } 356 1.1 simonb #endif 357 1.1 simonb 358 1.1 simonb sbjcn_config(ch); 359 1.1 simonb 360 1.1 simonb callout_reset(&ch->ch_callout, hz/10, sbjcn_callout, ch); 361 1.1 simonb 362 1.1 simonb SET(ch->ch_hwflags, SBJCN_HW_DEV_OK); 363 1.1 simonb } 364 1.1 simonb 365 1.1 simonb int 366 1.1 simonb sbjcn_speed(long speed, long *brcp) 367 1.1 simonb { 368 1.1 simonb #define divrnd(n, q) (((n)*2/(q)+1)/2) /* divide and round off */ 369 1.1 simonb 370 1.1 simonb int x, err; 371 1.1 simonb int frequency = 100000000; 372 1.1 simonb 373 1.1 simonb *brcp = divrnd(frequency / 20, speed) - 1; 374 1.1 simonb 375 1.1 simonb if (speed <= 0) 376 1.1 simonb return (-1); 377 1.1 simonb x = divrnd(frequency / 20, speed); 378 1.1 simonb if (x <= 0) 379 1.1 simonb return (-1); 380 1.1 simonb err = divrnd(((quad_t)frequency) * 1000 / 20, speed * x) - 1000; 381 1.1 simonb if (err < 0) 382 1.1 simonb err = -err; 383 1.1 simonb if (err > SBJCN_TOLERANCE) 384 1.1 simonb return (-1); 385 1.1 simonb *brcp = x - 1; 386 1.1 simonb return (0); 387 1.1 simonb 388 1.1 simonb #undef divrnd 389 1.1 simonb } 390 1.1 simonb 391 1.1 simonb #ifdef SBJCN_DEBUG 392 1.1 simonb void sbjcn_status(struct sbjcn_channel *, char *); 393 1.1 simonb 394 1.1 simonb int sbjcn_debug = 1 /* XXXCGD */; 395 1.1 simonb 396 1.1 simonb void 397 1.1 simonb sbjcn_status(struct sbjcn_channel *ch, char *str) 398 1.1 simonb { 399 1.1 simonb struct sbjcn_softc *sc = ch->ch_sc; 400 1.1 simonb struct tty *tp = ch->ch_tty; 401 1.1 simonb 402 1.26 matt aprint_normal_dev(sc->sc_dev, 403 1.26 matt "chan %d: %s %sclocal %sdcd %sts_carr_on %sdtr %stx_stopped\n", 404 1.26 matt ch->ch_num, str, 405 1.1 simonb ISSET(tp->t_cflag, CLOCAL) ? "+" : "-", 406 1.1 simonb ISSET(ch->ch_iports, ch->ch_i_dcd) ? "+" : "-", 407 1.1 simonb ISSET(tp->t_state, TS_CARR_ON) ? "+" : "-", 408 1.1 simonb ISSET(ch->ch_oports, ch->ch_o_dtr) ? "+" : "-", 409 1.1 simonb ch->ch_tx_stopped ? "+" : "-"); 410 1.1 simonb 411 1.26 matt aprint_normal_dev(sc->sc_dev, 412 1.26 matt "chan %d: %s %scrtscts %scts %sts_ttstop %srts %xrx_flags\n", 413 1.26 matt ch->ch_num, str, 414 1.1 simonb ISSET(tp->t_cflag, CRTSCTS) ? "+" : "-", 415 1.1 simonb ISSET(ch->ch_iports, ch->ch_i_cts) ? "+" : "-", 416 1.1 simonb ISSET(tp->t_state, TS_TTSTOP) ? "+" : "-", 417 1.1 simonb ISSET(ch->ch_oports, ch->ch_o_rts) ? "+" : "-", 418 1.1 simonb ch->ch_rx_flags); 419 1.1 simonb } 420 1.1 simonb #endif 421 1.1 simonb 422 1.1 simonb #if defined(DDB) || defined(KGDB) 423 1.1 simonb static void 424 1.1 simonb sbjcn_enable_debugport(struct sbjcn_channel *ch) 425 1.1 simonb { 426 1.1 simonb int s; 427 1.1 simonb 428 1.1 simonb /* Turn on line break interrupt, set carrier. */ 429 1.1 simonb s = splserial(); 430 1.1 simonb 431 1.1 simonb ch->ch_imr = 0x04; 432 1.1 simonb SET(ch->ch_oports, ch->ch_o_dtr | ch->ch_o_rts); 433 1.1 simonb 434 1.1 simonb splx(s); 435 1.1 simonb } 436 1.1 simonb #endif 437 1.1 simonb 438 1.1 simonb void 439 1.1 simonb sbjcn_config(struct sbjcn_channel *ch) 440 1.1 simonb { 441 1.1 simonb 442 1.1 simonb /* Disable interrupts before configuring the device. */ 443 1.1 simonb ch->ch_imr = 0x00; 444 1.1 simonb 445 1.1 simonb #ifdef DDB 446 1.1 simonb if (ISSET(ch->ch_hwflags, SBJCN_HW_CONSOLE)) 447 1.1 simonb sbjcn_enable_debugport(ch); 448 1.1 simonb #endif 449 1.1 simonb 450 1.1 simonb #ifdef KGDB 451 1.1 simonb /* 452 1.1 simonb * Allow kgdb to "take over" this port. If this is 453 1.1 simonb * the kgdb device, it has exclusive use. 454 1.1 simonb */ 455 1.1 simonb if (ISSET(ch->ch_hwflags, SBJCN_HW_KGDB)) 456 1.1 simonb sbjcn_enable_debugport(ch); 457 1.1 simonb #endif 458 1.1 simonb } 459 1.1 simonb 460 1.1 simonb void 461 1.1 simonb sbjcn_shutdown(struct sbjcn_channel *ch) 462 1.1 simonb { 463 1.1 simonb struct tty *tp = ch->ch_tty; 464 1.1 simonb int s; 465 1.1 simonb 466 1.1 simonb s = splserial(); 467 1.1 simonb 468 1.1 simonb /* If we were asserting flow control, then deassert it. */ 469 1.1 simonb SET(ch->ch_rx_flags, RX_IBUF_BLOCKED); 470 1.1 simonb sbjcn_dohwiflow(ch); 471 1.1 simonb 472 1.1 simonb /* Clear any break condition set with TIOCSBRK. */ 473 1.1 simonb sbjcn_break(ch, 0); 474 1.1 simonb 475 1.1 simonb /* 476 1.1 simonb * Hang up if necessary. Wait a bit, so the other side has time to 477 1.1 simonb * notice even if we immediately open the port again. 478 1.1 simonb */ 479 1.1 simonb if (ISSET(tp->t_cflag, HUPCL)) { 480 1.1 simonb sbjcn_modem(ch, 0); 481 1.1 simonb (void) tsleep(ch, TTIPRI, ttclos, hz); 482 1.1 simonb } 483 1.1 simonb 484 1.1 simonb /* Turn off interrupts. */ 485 1.1 simonb #ifdef DDB 486 1.1 simonb if (ISSET(ch->ch_hwflags, SBJCN_HW_CONSOLE)) 487 1.1 simonb ch->ch_imr = 0x04; /* interrupt on break */ 488 1.1 simonb else 489 1.1 simonb #endif 490 1.1 simonb ch->ch_imr = 0; 491 1.1 simonb 492 1.1 simonb splx(s); 493 1.1 simonb } 494 1.1 simonb 495 1.1 simonb int 496 1.13 ad sbjcnopen(dev_t dev, int flag, int mode, struct lwp *l) 497 1.1 simonb { 498 1.1 simonb int chan = SBJCN_CHAN(dev); 499 1.1 simonb struct sbjcn_softc *sc; 500 1.1 simonb struct sbjcn_channel *ch; 501 1.1 simonb struct tty *tp; 502 1.1 simonb int s, s2; 503 1.1 simonb int error; 504 1.1 simonb 505 1.21 cegger sc = device_lookup_private(&sbjcn_cd, SBJCN_UNIT(dev)); 506 1.21 cegger if (sc == NULL) 507 1.1 simonb return (ENXIO); 508 1.21 cegger 509 1.1 simonb ch = &sc->sc_channels[chan]; 510 1.1 simonb if (!ISSET(ch->ch_hwflags, SBJCN_HW_DEV_OK) || ch->ch_rbuf == NULL) 511 1.1 simonb return (ENXIO); 512 1.1 simonb 513 1.1 simonb #ifdef KGDB 514 1.1 simonb /* 515 1.1 simonb * If this is the kgdb port, no other use is permitted. 516 1.1 simonb */ 517 1.1 simonb if (ISSET(ch->ch_hwflags, SBJCN_HW_KGDB)) 518 1.1 simonb return (EBUSY); 519 1.1 simonb #endif 520 1.1 simonb 521 1.1 simonb tp = ch->ch_tty; 522 1.1 simonb 523 1.14 elad if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) 524 1.1 simonb return (EBUSY); 525 1.1 simonb 526 1.1 simonb s = spltty(); 527 1.1 simonb 528 1.1 simonb /* 529 1.1 simonb * Do the following iff this is a first open. 530 1.1 simonb */ 531 1.1 simonb if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 532 1.1 simonb struct termios t; 533 1.1 simonb 534 1.1 simonb tp->t_dev = dev; 535 1.1 simonb 536 1.1 simonb s2 = splserial(); 537 1.1 simonb 538 1.1 simonb /* Turn on receive, break, and status change interrupts. */ 539 1.1 simonb ch->ch_imr = 0xe; 540 1.1 simonb 541 1.1 simonb /* Fetch the current modem control status, needed later. */ 542 1.1 simonb ch->ch_iports = 0; 543 1.1 simonb ch->ch_iports_delta = 0; 544 1.1 simonb splx(s2); 545 1.1 simonb 546 1.1 simonb /* 547 1.1 simonb * Initialize the termios status to the defaults. Add in the 548 1.1 simonb * sticky bits from TIOCSFLAGS. 549 1.1 simonb */ 550 1.1 simonb t.c_ispeed = 0; 551 1.1 simonb if (ISSET(ch->ch_hwflags, SBJCN_HW_CONSOLE)) { 552 1.1 simonb t.c_ospeed = sbjcn_cons_rate; 553 1.1 simonb t.c_cflag = sbjcn_cons_cflag; 554 1.1 simonb } else { 555 1.1 simonb t.c_ospeed = TTYDEF_SPEED; 556 1.1 simonb t.c_cflag = TTYDEF_CFLAG; 557 1.1 simonb } 558 1.1 simonb if (ISSET(ch->ch_swflags, TIOCFLAG_CLOCAL)) 559 1.1 simonb SET(t.c_cflag, CLOCAL); 560 1.1 simonb if (ISSET(ch->ch_swflags, TIOCFLAG_CRTSCTS)) 561 1.1 simonb SET(t.c_cflag, CRTSCTS); 562 1.1 simonb if (ISSET(ch->ch_swflags, TIOCFLAG_MDMBUF)) 563 1.1 simonb SET(t.c_cflag, MDMBUF); 564 1.1 simonb /* Make sure sbjcn_param() will do something. */ 565 1.1 simonb tp->t_ospeed = 0; 566 1.1 simonb (void) sbjcn_param(tp, &t); 567 1.1 simonb tp->t_iflag = TTYDEF_IFLAG; 568 1.1 simonb tp->t_oflag = TTYDEF_OFLAG; 569 1.1 simonb tp->t_lflag = TTYDEF_LFLAG; 570 1.1 simonb ttychars(tp); 571 1.1 simonb ttsetwater(tp); 572 1.1 simonb 573 1.1 simonb s2 = splserial(); 574 1.1 simonb 575 1.1 simonb /* 576 1.1 simonb * Turn on DTR. We must always do this, even if carrier is not 577 1.1 simonb * present, because otherwise we'd have to use TIOCSDTR 578 1.1 simonb * immediately after setting CLOCAL, which applications do not 579 1.1 simonb * expect. We always assert DTR while the device is open 580 1.1 simonb * unless explicitly requested to deassert it. 581 1.1 simonb */ 582 1.1 simonb sbjcn_modem(ch, 1); 583 1.1 simonb 584 1.1 simonb /* Clear the input ring, and unblock. */ 585 1.1 simonb ch->ch_rbput = ch->ch_rbget = ch->ch_rbuf; 586 1.1 simonb ch->ch_rbavail = sbjcn_rbuf_size; 587 1.1 simonb sbjcn_iflush(ch); 588 1.1 simonb CLR(ch->ch_rx_flags, RX_ANY_BLOCK); 589 1.1 simonb sbjcn_dohwiflow(ch); 590 1.1 simonb 591 1.1 simonb #ifdef SBJCN_DEBUG 592 1.1 simonb if (sbjcn_debug) 593 1.1 simonb sbjcn_status(ch, "sbjcnopen "); 594 1.1 simonb #endif 595 1.1 simonb 596 1.1 simonb splx(s2); 597 1.1 simonb } 598 1.1 simonb 599 1.1 simonb splx(s); 600 1.1 simonb 601 1.1 simonb error = ttyopen(tp, SBJCN_DIALOUT(dev), ISSET(flag, O_NONBLOCK)); 602 1.1 simonb if (error) 603 1.1 simonb goto bad; 604 1.1 simonb 605 1.1 simonb error = (*tp->t_linesw->l_open)(dev, tp); 606 1.1 simonb if (error) 607 1.1 simonb goto bad; 608 1.1 simonb 609 1.1 simonb return (0); 610 1.1 simonb 611 1.1 simonb bad: 612 1.1 simonb if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 613 1.1 simonb /* 614 1.1 simonb * We failed to open the device, and nobody else had it opened. 615 1.1 simonb * Clean up the state as appropriate. 616 1.1 simonb */ 617 1.1 simonb sbjcn_shutdown(ch); 618 1.1 simonb } 619 1.1 simonb 620 1.1 simonb return (error); 621 1.1 simonb } 622 1.1 simonb 623 1.1 simonb int 624 1.1 simonb sbjcnclose(dev_t dev, int flag, int mode, struct proc *p) 625 1.1 simonb { 626 1.21 cegger struct sbjcn_softc *sc = device_lookup_private(&sbjcn_cd, SBJCN_UNIT(dev)); 627 1.1 simonb struct sbjcn_channel *ch = &sc->sc_channels[SBJCN_CHAN(dev)]; 628 1.1 simonb struct tty *tp = ch->ch_tty; 629 1.1 simonb 630 1.1 simonb /* XXX This is for cons.c. */ 631 1.1 simonb if (!ISSET(tp->t_state, TS_ISOPEN)) 632 1.1 simonb return (0); 633 1.1 simonb 634 1.1 simonb (*tp->t_linesw->l_close)(tp, flag); 635 1.1 simonb ttyclose(tp); 636 1.1 simonb 637 1.1 simonb if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 638 1.1 simonb /* 639 1.1 simonb * Although we got a last close, the device may still be in 640 1.1 simonb * use; e.g. if this was the dialout node, and there are still 641 1.1 simonb * processes waiting for carrier on the non-dialout node. 642 1.1 simonb */ 643 1.1 simonb sbjcn_shutdown(ch); 644 1.1 simonb } 645 1.1 simonb 646 1.1 simonb return (0); 647 1.1 simonb } 648 1.1 simonb 649 1.1 simonb int 650 1.1 simonb sbjcnread(dev_t dev, struct uio *uio, int flag) 651 1.1 simonb { 652 1.21 cegger struct sbjcn_softc *sc = device_lookup_private(&sbjcn_cd, SBJCN_UNIT(dev)); 653 1.1 simonb struct sbjcn_channel *ch = &sc->sc_channels[SBJCN_CHAN(dev)]; 654 1.1 simonb struct tty *tp = ch->ch_tty; 655 1.1 simonb 656 1.1 simonb return ((*tp->t_linesw->l_read)(tp, uio, flag)); 657 1.1 simonb } 658 1.1 simonb 659 1.1 simonb int 660 1.1 simonb sbjcnwrite(dev_t dev, struct uio *uio, int flag) 661 1.1 simonb { 662 1.21 cegger struct sbjcn_softc *sc = device_lookup_private(&sbjcn_cd, SBJCN_UNIT(dev)); 663 1.1 simonb struct sbjcn_channel *ch = &sc->sc_channels[SBJCN_CHAN(dev)]; 664 1.1 simonb struct tty *tp = ch->ch_tty; 665 1.1 simonb 666 1.1 simonb return ((*tp->t_linesw->l_write)(tp, uio, flag)); 667 1.1 simonb } 668 1.1 simonb 669 1.1 simonb struct tty * 670 1.1 simonb sbjcntty(dev_t dev) 671 1.1 simonb { 672 1.21 cegger struct sbjcn_softc *sc = device_lookup_private(&sbjcn_cd, SBJCN_UNIT(dev)); 673 1.1 simonb struct sbjcn_channel *ch = &sc->sc_channels[SBJCN_CHAN(dev)]; 674 1.1 simonb struct tty *tp = ch->ch_tty; 675 1.1 simonb 676 1.1 simonb return (tp); 677 1.1 simonb } 678 1.1 simonb 679 1.1 simonb int 680 1.16 christos sbjcnioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 681 1.1 simonb { 682 1.21 cegger struct sbjcn_softc *sc = device_lookup_private(&sbjcn_cd, SBJCN_UNIT(dev)); 683 1.1 simonb struct sbjcn_channel *ch = &sc->sc_channels[SBJCN_CHAN(dev)]; 684 1.1 simonb struct tty *tp = ch->ch_tty; 685 1.1 simonb int error; 686 1.1 simonb int s; 687 1.1 simonb 688 1.1 simonb error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, p); 689 1.1 simonb if (error >= 0) 690 1.1 simonb return (error); 691 1.1 simonb 692 1.1 simonb error = ttioctl(tp, cmd, data, flag, p); 693 1.1 simonb if (error >= 0) 694 1.1 simonb return (error); 695 1.1 simonb 696 1.1 simonb error = 0; 697 1.1 simonb 698 1.1 simonb s = splserial(); 699 1.1 simonb 700 1.1 simonb switch (cmd) { 701 1.1 simonb case TIOCSBRK: 702 1.1 simonb sbjcn_break(ch, 1); 703 1.1 simonb break; 704 1.1 simonb 705 1.1 simonb case TIOCCBRK: 706 1.1 simonb sbjcn_break(ch, 0); 707 1.1 simonb break; 708 1.1 simonb 709 1.1 simonb case TIOCSDTR: 710 1.1 simonb sbjcn_modem(ch, 1); 711 1.1 simonb break; 712 1.1 simonb 713 1.1 simonb case TIOCCDTR: 714 1.1 simonb sbjcn_modem(ch, 0); 715 1.1 simonb break; 716 1.1 simonb 717 1.1 simonb case TIOCGFLAGS: 718 1.1 simonb *(int *)data = ch->ch_swflags; 719 1.1 simonb break; 720 1.1 simonb 721 1.1 simonb case TIOCSFLAGS: 722 1.15 elad error = kauth_authorize_device_tty(l->l_cred, 723 1.15 elad KAUTH_DEVICE_TTY_PRIVSET, tp); 724 1.1 simonb if (error) 725 1.1 simonb break; 726 1.1 simonb ch->ch_swflags = *(int *)data; 727 1.1 simonb break; 728 1.1 simonb 729 1.1 simonb case TIOCMSET: 730 1.1 simonb case TIOCMBIS: 731 1.1 simonb case TIOCMBIC: 732 1.1 simonb tiocm_to_sbjcn(ch, cmd, *(int *)data); 733 1.1 simonb break; 734 1.1 simonb 735 1.1 simonb case TIOCMGET: 736 1.1 simonb *(int *)data = sbjcn_to_tiocm(ch); 737 1.1 simonb break; 738 1.1 simonb 739 1.1 simonb default: 740 1.1 simonb error = ENOTTY; 741 1.1 simonb break; 742 1.1 simonb } 743 1.1 simonb 744 1.1 simonb splx(s); 745 1.1 simonb 746 1.1 simonb #ifdef SBJCN_DEBUG 747 1.1 simonb if (sbjcn_debug) 748 1.1 simonb sbjcn_status(ch, "sbjcn_ioctl "); 749 1.1 simonb #endif 750 1.1 simonb 751 1.1 simonb return (error); 752 1.1 simonb } 753 1.1 simonb 754 1.1 simonb integrate void 755 1.1 simonb sbjcn_schedrx(struct sbjcn_channel *ch) 756 1.1 simonb { 757 1.1 simonb 758 1.1 simonb ch->ch_rx_ready = 1; 759 1.1 simonb 760 1.1 simonb /* Next callout will detect this flag. */ 761 1.1 simonb } 762 1.1 simonb 763 1.1 simonb void 764 1.1 simonb sbjcn_break(struct sbjcn_channel *ch, int onoff) 765 1.1 simonb { 766 1.1 simonb /* XXXKW do something? */ 767 1.1 simonb } 768 1.1 simonb 769 1.1 simonb void 770 1.1 simonb sbjcn_modem(struct sbjcn_channel *ch, int onoff) 771 1.1 simonb { 772 1.1 simonb 773 1.1 simonb if (ch->ch_o_dtr == 0) 774 1.1 simonb return; 775 1.1 simonb 776 1.1 simonb if (onoff) 777 1.1 simonb SET(ch->ch_oports, ch->ch_o_dtr); 778 1.1 simonb else 779 1.1 simonb CLR(ch->ch_oports, ch->ch_o_dtr); 780 1.1 simonb 781 1.1 simonb if (!ch->ch_heldchange) { 782 1.1 simonb if (ch->ch_tx_busy) { 783 1.1 simonb ch->ch_heldtbc = ch->ch_tbc; 784 1.1 simonb ch->ch_tbc = 0; 785 1.1 simonb ch->ch_heldchange = 1; 786 1.1 simonb } else 787 1.1 simonb sbjcn_loadchannelregs(ch); 788 1.1 simonb } 789 1.1 simonb } 790 1.1 simonb 791 1.1 simonb void 792 1.1 simonb tiocm_to_sbjcn(struct sbjcn_channel *ch, int how, int ttybits) 793 1.1 simonb { 794 1.1 simonb u_char bits; 795 1.1 simonb 796 1.1 simonb bits = 0; 797 1.1 simonb if (ISSET(ttybits, TIOCM_DTR)) 798 1.1 simonb SET(bits, ch->ch_o_dtr); 799 1.1 simonb if (ISSET(ttybits, TIOCM_RTS)) 800 1.1 simonb SET(bits, ch->ch_o_rts); 801 1.1 simonb 802 1.1 simonb switch (how) { 803 1.1 simonb case TIOCMBIC: 804 1.1 simonb CLR(ch->ch_oports, bits); 805 1.1 simonb break; 806 1.1 simonb 807 1.1 simonb case TIOCMBIS: 808 1.1 simonb SET(ch->ch_oports, bits); 809 1.1 simonb break; 810 1.1 simonb 811 1.1 simonb case TIOCMSET: 812 1.1 simonb ch->ch_oports = bits; 813 1.1 simonb break; 814 1.1 simonb } 815 1.1 simonb 816 1.1 simonb if (!ch->ch_heldchange) { 817 1.1 simonb if (ch->ch_tx_busy) { 818 1.1 simonb ch->ch_heldtbc = ch->ch_tbc; 819 1.1 simonb ch->ch_tbc = 0; 820 1.1 simonb ch->ch_heldchange = 1; 821 1.1 simonb } else 822 1.1 simonb sbjcn_loadchannelregs(ch); 823 1.1 simonb } 824 1.1 simonb } 825 1.1 simonb 826 1.1 simonb int 827 1.1 simonb sbjcn_to_tiocm(struct sbjcn_channel *ch) 828 1.1 simonb { 829 1.1 simonb u_char hwbits; 830 1.1 simonb int ttybits = 0; 831 1.1 simonb 832 1.1 simonb hwbits = ch->ch_oports; 833 1.1 simonb if (ISSET(hwbits, ch->ch_o_dtr)) 834 1.1 simonb SET(ttybits, TIOCM_DTR); 835 1.1 simonb if (ISSET(hwbits, ch->ch_o_rts)) 836 1.1 simonb SET(ttybits, TIOCM_RTS); 837 1.1 simonb 838 1.1 simonb hwbits = ch->ch_iports; 839 1.1 simonb if (ISSET(hwbits, ch->ch_i_dcd)) 840 1.1 simonb SET(ttybits, TIOCM_CD); 841 1.1 simonb if (ISSET(hwbits, ch->ch_i_cts)) 842 1.1 simonb SET(ttybits, TIOCM_CTS); 843 1.1 simonb if (ISSET(hwbits, ch->ch_i_dsr)) 844 1.1 simonb SET(ttybits, TIOCM_DSR); 845 1.1 simonb if (ISSET(hwbits, ch->ch_i_ri)) 846 1.1 simonb SET(ttybits, TIOCM_RI); 847 1.1 simonb 848 1.1 simonb if (ch->ch_imr != 0) 849 1.1 simonb SET(ttybits, TIOCM_LE); 850 1.1 simonb 851 1.1 simonb return (ttybits); 852 1.1 simonb } 853 1.1 simonb 854 1.1 simonb static int 855 1.22 dsl cflag2modes(tcflag_t cflag, u_char *mode1p, u_char *mode2p) 856 1.1 simonb { 857 1.1 simonb u_char mode1; 858 1.1 simonb u_char mode2; 859 1.1 simonb int err = 0; 860 1.1 simonb 861 1.1 simonb mode1 = mode2 = 0; 862 1.1 simonb 863 1.1 simonb switch (ISSET(cflag, CSIZE)) { 864 1.1 simonb case CS7: 865 1.1 simonb mode1 |= 2; /* XXX */ 866 1.1 simonb break; 867 1.1 simonb default: 868 1.1 simonb err = -1; 869 1.1 simonb /* FALLTHRU for sanity */ 870 1.1 simonb case CS8: 871 1.1 simonb mode1 |= 3; /* XXX */ 872 1.1 simonb break; 873 1.1 simonb } 874 1.1 simonb if (!ISSET(cflag, PARENB)) 875 1.1 simonb mode1 |= 2 << 3; 876 1.1 simonb else { 877 1.1 simonb mode1 |= 0 << 3; 878 1.1 simonb if (ISSET(cflag, PARODD)) 879 1.1 simonb mode1 |= 1 << 2; 880 1.1 simonb } 881 1.1 simonb 882 1.1 simonb if (ISSET(cflag, CSTOPB)) 883 1.1 simonb mode2 |= 1 << 3; /* two stop bits XXX not std */ 884 1.1 simonb 885 1.1 simonb if (ISSET(cflag, CRTSCTS)) { 886 1.1 simonb mode1 |= 1 << 7; 887 1.1 simonb mode2 |= 1 << 4; 888 1.1 simonb } 889 1.1 simonb 890 1.1 simonb *mode1p = mode1; 891 1.1 simonb *mode2p = mode2; 892 1.1 simonb return (err); 893 1.1 simonb } 894 1.1 simonb 895 1.1 simonb int 896 1.1 simonb sbjcn_param(struct tty *tp, struct termios *t) 897 1.1 simonb { 898 1.21 cegger struct sbjcn_softc *sc = device_lookup_private(&sbjcn_cd, SBJCN_UNIT(tp->t_dev)); 899 1.1 simonb struct sbjcn_channel *ch = &sc->sc_channels[SBJCN_CHAN(tp->t_dev)]; 900 1.1 simonb long brc; 901 1.1 simonb u_char mode1, mode2; 902 1.1 simonb int s; 903 1.1 simonb 904 1.1 simonb /* XXX reset to console parameters if console? */ 905 1.1 simonb #if 0 906 1.1 simonb XXX disable, enable. 907 1.1 simonb #endif 908 1.1 simonb 909 1.1 simonb /* Check requested parameters. */ 910 1.1 simonb if (sbjcn_speed(t->c_ospeed, &brc) < 0) 911 1.1 simonb return (EINVAL); 912 1.1 simonb if (t->c_ispeed && t->c_ispeed != t->c_ospeed) 913 1.1 simonb return (EINVAL); 914 1.1 simonb 915 1.1 simonb /* 916 1.1 simonb * For the console, always force CLOCAL and !HUPCL, so that the port 917 1.1 simonb * is always active. 918 1.1 simonb */ 919 1.1 simonb if (ISSET(ch->ch_swflags, TIOCFLAG_SOFTCAR) || 920 1.1 simonb ISSET(ch->ch_hwflags, SBJCN_HW_CONSOLE)) { 921 1.1 simonb SET(t->c_cflag, CLOCAL); 922 1.1 simonb CLR(t->c_cflag, HUPCL); 923 1.1 simonb } 924 1.1 simonb 925 1.1 simonb /* 926 1.1 simonb * If there were no changes, don't do anything. This avoids dropping 927 1.1 simonb * input and improves performance when all we did was frob things like 928 1.1 simonb * VMIN and VTIME. 929 1.1 simonb */ 930 1.1 simonb if (tp->t_ospeed == t->c_ospeed && 931 1.1 simonb tp->t_cflag == t->c_cflag) 932 1.1 simonb return (0); 933 1.1 simonb 934 1.1 simonb if (cflag2modes(t->c_cflag, &mode1, &mode2) < 0) 935 1.1 simonb return (EINVAL); 936 1.1 simonb 937 1.1 simonb s = splserial(); 938 1.1 simonb 939 1.1 simonb ch->ch_mode1 = mode1; 940 1.1 simonb ch->ch_mode2 = mode2; 941 1.1 simonb 942 1.1 simonb /* 943 1.1 simonb * If we're not in a mode that assumes a connection is present, then 944 1.1 simonb * ignore carrier changes. 945 1.1 simonb */ 946 1.1 simonb if (ISSET(t->c_cflag, CLOCAL | MDMBUF)) 947 1.1 simonb ch->ch_i_dcd = 0; 948 1.1 simonb else 949 1.1 simonb ch->ch_i_dcd = ch->ch_i_dcd_pin; 950 1.1 simonb /* 951 1.1 simonb * Set the flow control pins depending on the current flow control 952 1.1 simonb * mode. 953 1.1 simonb */ 954 1.1 simonb if (ISSET(t->c_cflag, CRTSCTS)) { 955 1.1 simonb ch->ch_o_dtr = ch->ch_o_dtr_pin; 956 1.1 simonb ch->ch_o_rts = ch->ch_o_rts_pin; 957 1.1 simonb ch->ch_i_cts = ch->ch_i_cts_pin; 958 1.1 simonb /* hw controle enable bits in mod regs set by cflag2modes */ 959 1.1 simonb } else if (ISSET(t->c_cflag, MDMBUF)) { 960 1.1 simonb /* 961 1.1 simonb * For DTR/DCD flow control, make sure we don't toggle DTR for 962 1.1 simonb * carrier detection. 963 1.1 simonb */ 964 1.1 simonb ch->ch_o_dtr = 0; 965 1.1 simonb ch->ch_o_rts = ch->ch_o_dtr_pin; 966 1.1 simonb ch->ch_i_cts = ch->ch_i_dcd_pin; 967 1.1 simonb } else { 968 1.1 simonb /* 969 1.1 simonb * If no flow control, then always set RTS. This will make 970 1.1 simonb * the other side happy if it mistakenly thinks we're doing 971 1.1 simonb * RTS/CTS flow control. 972 1.1 simonb */ 973 1.1 simonb ch->ch_o_dtr = ch->ch_o_dtr_pin | ch->ch_o_rts_pin; 974 1.1 simonb ch->ch_o_rts = 0; 975 1.1 simonb ch->ch_i_cts = 0; 976 1.1 simonb if (ISSET(ch->ch_oports, ch->ch_o_dtr_pin)) 977 1.1 simonb SET(ch->ch_oports, ch->ch_o_rts_pin); 978 1.1 simonb else 979 1.1 simonb CLR(ch->ch_oports, ch->ch_o_rts_pin); 980 1.1 simonb } 981 1.1 simonb /* XXX maybe mask the ports which generate intrs? */ 982 1.1 simonb 983 1.1 simonb ch->ch_brc = brc; 984 1.1 simonb 985 1.1 simonb /* XXX maybe set fifo-full receive mode if RTSCTS and high speed? */ 986 1.1 simonb 987 1.1 simonb /* And copy to tty. */ 988 1.1 simonb tp->t_ispeed = 0; 989 1.1 simonb tp->t_ospeed = t->c_ospeed; 990 1.1 simonb tp->t_cflag = t->c_cflag; 991 1.1 simonb 992 1.1 simonb if (!ch->ch_heldchange) { 993 1.1 simonb if (ch->ch_tx_busy) { 994 1.1 simonb ch->ch_heldtbc = ch->ch_tbc; 995 1.1 simonb ch->ch_tbc = 0; 996 1.1 simonb ch->ch_heldchange = 1; 997 1.1 simonb } else 998 1.1 simonb sbjcn_loadchannelregs(ch); 999 1.1 simonb } 1000 1.1 simonb 1001 1.1 simonb if (!ISSET(t->c_cflag, CHWFLOW)) { 1002 1.1 simonb /* Disable the high water mark. */ 1003 1.1 simonb ch->ch_r_hiwat = 0; 1004 1.1 simonb ch->ch_r_lowat = 0; 1005 1.1 simonb if (ISSET(ch->ch_rx_flags, RX_TTY_OVERFLOWED)) { 1006 1.1 simonb CLR(ch->ch_rx_flags, RX_TTY_OVERFLOWED); 1007 1.1 simonb sbjcn_schedrx(ch); 1008 1.1 simonb } 1009 1.1 simonb if (ISSET(ch->ch_rx_flags, RX_TTY_BLOCKED|RX_IBUF_BLOCKED)) { 1010 1.1 simonb CLR(ch->ch_rx_flags, RX_TTY_BLOCKED|RX_IBUF_BLOCKED); 1011 1.1 simonb sbjcn_dohwiflow(ch); 1012 1.1 simonb } 1013 1.1 simonb } else { 1014 1.1 simonb ch->ch_r_hiwat = sbjcn_rbuf_hiwat; 1015 1.1 simonb ch->ch_r_lowat = sbjcn_rbuf_lowat; 1016 1.1 simonb } 1017 1.1 simonb 1018 1.1 simonb splx(s); 1019 1.1 simonb 1020 1.1 simonb /* 1021 1.1 simonb * Update the tty layer's idea of the carrier bit, in case we changed 1022 1.1 simonb * CLOCAL or MDMBUF. We don't hang up here; we only do that by 1023 1.1 simonb * explicit request. 1024 1.1 simonb */ 1025 1.1 simonb (void) (*tp->t_linesw->l_modem)(tp, 1026 1.1 simonb ISSET(ch->ch_iports, ch->ch_i_dcd)); 1027 1.1 simonb 1028 1.1 simonb #ifdef SBJCN_DEBUG 1029 1.1 simonb if (sbjcn_debug) 1030 1.1 simonb sbjcn_status(ch, "sbjcnparam "); 1031 1.1 simonb #endif 1032 1.1 simonb 1033 1.1 simonb if (!ISSET(t->c_cflag, CHWFLOW)) { 1034 1.1 simonb if (ch->ch_tx_stopped) { 1035 1.1 simonb ch->ch_tx_stopped = 0; 1036 1.1 simonb sbjcn_start(tp); 1037 1.1 simonb } 1038 1.1 simonb } 1039 1.1 simonb 1040 1.1 simonb return (0); 1041 1.1 simonb } 1042 1.1 simonb 1043 1.1 simonb void 1044 1.1 simonb sbjcn_iflush(struct sbjcn_channel *ch) 1045 1.1 simonb { 1046 1.1 simonb uint64_t reg; 1047 1.1 simonb int timo; 1048 1.1 simonb 1049 1.1 simonb timo = 50000; 1050 1.1 simonb /* flush any pending I/O */ 1051 1.1 simonb while (((reg = READ_REG(ch->ch_input_reg)) != 0) && --timo) 1052 1.1 simonb ; 1053 1.1 simonb 1054 1.1 simonb #ifdef DIAGNOSTIC 1055 1.1 simonb if (!timo) 1056 1.26 matt aprint_error_dev(ch->ch_sc->sc_dev, 1057 1.26 matt "sbjcn_iflush timeout %02x\n", reg); 1058 1.1 simonb #endif 1059 1.1 simonb } 1060 1.1 simonb 1061 1.1 simonb void 1062 1.1 simonb sbjcn_loadchannelregs(struct sbjcn_channel *ch) 1063 1.1 simonb { 1064 1.1 simonb } 1065 1.1 simonb 1066 1.1 simonb int 1067 1.1 simonb sbjcn_hwiflow(struct tty *tp, int block) 1068 1.1 simonb { 1069 1.21 cegger struct sbjcn_softc *sc = device_lookup_private(&sbjcn_cd, SBJCN_UNIT(tp->t_dev)); 1070 1.1 simonb struct sbjcn_channel *ch = &sc->sc_channels[SBJCN_CHAN(tp->t_dev)]; 1071 1.1 simonb int s; 1072 1.1 simonb 1073 1.1 simonb if (ch->ch_o_rts == 0) 1074 1.1 simonb return (0); 1075 1.1 simonb 1076 1.1 simonb s = splserial(); 1077 1.1 simonb if (block) { 1078 1.1 simonb if (!ISSET(ch->ch_rx_flags, RX_TTY_BLOCKED)) { 1079 1.1 simonb SET(ch->ch_rx_flags, RX_TTY_BLOCKED); 1080 1.1 simonb sbjcn_dohwiflow(ch); 1081 1.1 simonb } 1082 1.1 simonb } else { 1083 1.1 simonb if (ISSET(ch->ch_rx_flags, RX_TTY_OVERFLOWED)) { 1084 1.1 simonb CLR(ch->ch_rx_flags, RX_TTY_OVERFLOWED); 1085 1.1 simonb sbjcn_schedrx(ch); 1086 1.1 simonb } 1087 1.1 simonb if (ISSET(ch->ch_rx_flags, RX_TTY_BLOCKED)) { 1088 1.1 simonb CLR(ch->ch_rx_flags, RX_TTY_BLOCKED); 1089 1.1 simonb sbjcn_dohwiflow(ch); 1090 1.1 simonb } 1091 1.1 simonb } 1092 1.1 simonb splx(s); 1093 1.1 simonb return (1); 1094 1.1 simonb } 1095 1.1 simonb 1096 1.1 simonb /* 1097 1.1 simonb * (un)block input via hw flowcontrol 1098 1.1 simonb */ 1099 1.1 simonb void 1100 1.1 simonb sbjcn_dohwiflow(struct sbjcn_channel *ch) 1101 1.1 simonb { 1102 1.1 simonb 1103 1.1 simonb if (ch->ch_o_rts == 0) 1104 1.1 simonb return; 1105 1.1 simonb 1106 1.1 simonb if (ISSET(ch->ch_rx_flags, RX_ANY_BLOCK)) { 1107 1.1 simonb CLR(ch->ch_oports, ch->ch_o_rts); 1108 1.1 simonb CLR(ch->ch_oports_active, ch->ch_o_rts); 1109 1.1 simonb } else { 1110 1.1 simonb SET(ch->ch_oports, ch->ch_o_rts); 1111 1.1 simonb SET(ch->ch_oports_active, ch->ch_o_rts); 1112 1.1 simonb } 1113 1.1 simonb } 1114 1.1 simonb 1115 1.1 simonb void 1116 1.1 simonb sbjcn_start(struct tty *tp) 1117 1.1 simonb { 1118 1.21 cegger struct sbjcn_softc *sc = device_lookup_private(&sbjcn_cd, SBJCN_UNIT(tp->t_dev)); 1119 1.1 simonb struct sbjcn_channel *ch = &sc->sc_channels[SBJCN_CHAN(tp->t_dev)]; 1120 1.1 simonb int s; 1121 1.1 simonb 1122 1.1 simonb s = spltty(); 1123 1.1 simonb if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) 1124 1.1 simonb goto out; 1125 1.1 simonb if (ch->ch_tx_stopped) 1126 1.1 simonb goto out; 1127 1.19 ad if (!ttypull(tp)) 1128 1.19 ad goto out; 1129 1.1 simonb 1130 1.1 simonb /* Grab the first contiguous region of buffer space. */ 1131 1.1 simonb { 1132 1.1 simonb u_char *tba; 1133 1.1 simonb int tbc; 1134 1.1 simonb 1135 1.1 simonb tba = tp->t_outq.c_cf; 1136 1.1 simonb tbc = ndqb(&tp->t_outq, 0); 1137 1.1 simonb 1138 1.1 simonb (void)splserial(); 1139 1.1 simonb 1140 1.1 simonb ch->ch_tba = tba; 1141 1.1 simonb ch->ch_tbc = tbc; 1142 1.1 simonb } 1143 1.1 simonb 1144 1.1 simonb SET(tp->t_state, TS_BUSY); 1145 1.1 simonb ch->ch_tx_busy = 1; 1146 1.1 simonb 1147 1.1 simonb /* Output the first chunk of the contiguous buffer. */ 1148 1.1 simonb { 1149 1.1 simonb while (ch->ch_tbc) { 1150 1.1 simonb uint64_t data; 1151 1.1 simonb int bytes, i; 1152 1.1 simonb 1153 1.1 simonb bytes = (ch->ch_tbc > 7) ? 7 : ch->ch_tbc; 1154 1.1 simonb data = bytes; 1155 1.1 simonb for (i=0; i<bytes; i++) { 1156 1.1 simonb data <<= 8; 1157 1.1 simonb data |= *ch->ch_tba++; 1158 1.1 simonb } 1159 1.1 simonb if (bytes < 7) 1160 1.1 simonb data <<= 56-(bytes<<3); 1161 1.1 simonb ch->ch_tbc -= bytes; 1162 1.1 simonb WRITE_REG(ch->ch_output_reg, data); 1163 1.1 simonb } 1164 1.1 simonb ch->ch_tx_busy = 0; 1165 1.1 simonb ch->ch_tx_done = 1; 1166 1.1 simonb } 1167 1.1 simonb out: 1168 1.1 simonb splx(s); 1169 1.1 simonb return; 1170 1.1 simonb } 1171 1.1 simonb 1172 1.1 simonb /* 1173 1.1 simonb * Stop output on a line. 1174 1.1 simonb */ 1175 1.1 simonb void 1176 1.1 simonb sbjcnstop(struct tty *tp, int flag) 1177 1.1 simonb { 1178 1.21 cegger struct sbjcn_softc *sc = device_lookup_private(&sbjcn_cd, SBJCN_UNIT(tp->t_dev)); 1179 1.1 simonb struct sbjcn_channel *ch = &sc->sc_channels[SBJCN_CHAN(tp->t_dev)]; 1180 1.1 simonb int s; 1181 1.1 simonb 1182 1.1 simonb s = splserial(); 1183 1.1 simonb if (ISSET(tp->t_state, TS_BUSY)) { 1184 1.1 simonb /* Stop transmitting at the next chunk. */ 1185 1.1 simonb ch->ch_tbc = 0; 1186 1.1 simonb ch->ch_heldtbc = 0; 1187 1.1 simonb if (!ISSET(tp->t_state, TS_TTSTOP)) 1188 1.1 simonb SET(tp->t_state, TS_FLUSH); 1189 1.1 simonb } 1190 1.1 simonb splx(s); 1191 1.1 simonb } 1192 1.1 simonb 1193 1.1 simonb void 1194 1.21 cegger sbjcn_diag(void *arg) 1195 1.1 simonb { 1196 1.1 simonb struct sbjcn_channel *ch = arg; 1197 1.1 simonb struct sbjcn_softc *sc = ch->ch_sc; 1198 1.1 simonb int overflows, floods; 1199 1.1 simonb int s; 1200 1.1 simonb 1201 1.1 simonb s = splserial(); 1202 1.1 simonb overflows = ch->ch_overflows; 1203 1.1 simonb ch->ch_overflows = 0; 1204 1.1 simonb floods = ch->ch_floods; 1205 1.1 simonb ch->ch_floods = 0; 1206 1.1 simonb ch->ch_errors = 0; 1207 1.1 simonb splx(s); 1208 1.1 simonb 1209 1.1 simonb log(LOG_WARNING, "%s: channel %d: %d fifo overflow%s, %d ibuf flood%s\n", 1210 1.26 matt device_xname(sc->sc_dev), ch->ch_num, 1211 1.1 simonb overflows, overflows == 1 ? "" : "s", 1212 1.1 simonb floods, floods == 1 ? "" : "s"); 1213 1.1 simonb } 1214 1.1 simonb 1215 1.1 simonb integrate void 1216 1.1 simonb sbjcn_rxsoft(struct sbjcn_channel *ch, struct tty *tp) 1217 1.1 simonb { 1218 1.1 simonb int (*rint)(int c, struct tty *tp) = tp->t_linesw->l_rint; 1219 1.1 simonb u_char *get, *end; 1220 1.1 simonb u_int cc, scc; 1221 1.1 simonb u_char sr; 1222 1.1 simonb int code; 1223 1.1 simonb int s; 1224 1.1 simonb 1225 1.1 simonb end = ch->ch_ebuf; 1226 1.1 simonb get = ch->ch_rbget; 1227 1.1 simonb scc = cc = sbjcn_rbuf_size - ch->ch_rbavail; 1228 1.1 simonb 1229 1.1 simonb if (cc == sbjcn_rbuf_size) { 1230 1.1 simonb ch->ch_floods++; 1231 1.1 simonb if (ch->ch_errors++ == 0) 1232 1.1 simonb callout_reset(&ch->ch_diag_callout, 60 * hz, 1233 1.1 simonb sbjcn_diag, ch); 1234 1.1 simonb } 1235 1.1 simonb 1236 1.1 simonb while (cc) { 1237 1.1 simonb code = get[0]; 1238 1.1 simonb sr = get[1]; 1239 1.1 simonb if (ISSET(sr, 0xf0)) { 1240 1.1 simonb if (ISSET(sr, 0x10)) { 1241 1.1 simonb ch->ch_overflows++; 1242 1.1 simonb if (ch->ch_errors++ == 0) 1243 1.1 simonb callout_reset(&ch->ch_diag_callout, 1244 1.1 simonb 60 * hz, sbjcn_diag, ch); 1245 1.1 simonb } 1246 1.1 simonb if (ISSET(sr, 0xc0)) 1247 1.1 simonb SET(code, TTY_FE); 1248 1.1 simonb if (ISSET(sr, 0x20)) 1249 1.1 simonb SET(code, TTY_PE); 1250 1.1 simonb } 1251 1.1 simonb if ((*rint)(code, tp) == -1) { 1252 1.1 simonb /* 1253 1.1 simonb * The line discipline's buffer is out of space. 1254 1.1 simonb */ 1255 1.1 simonb if (!ISSET(ch->ch_rx_flags, RX_TTY_BLOCKED)) { 1256 1.1 simonb /* 1257 1.1 simonb * We're either not using flow control, or the 1258 1.1 simonb * line discipline didn't tell us to block for 1259 1.1 simonb * some reason. Either way, we have no way to 1260 1.1 simonb * know when there's more space available, so 1261 1.1 simonb * just drop the rest of the data. 1262 1.1 simonb */ 1263 1.1 simonb get += cc << 1; 1264 1.1 simonb if (get >= end) 1265 1.1 simonb get -= sbjcn_rbuf_size << 1; 1266 1.1 simonb cc = 0; 1267 1.1 simonb } else { 1268 1.1 simonb /* 1269 1.1 simonb * Don't schedule any more receive processing 1270 1.1 simonb * until the line discipline tells us there's 1271 1.1 simonb * space available (through comhwiflow()). 1272 1.1 simonb * Leave the rest of the data in the input 1273 1.1 simonb * buffer. 1274 1.1 simonb */ 1275 1.1 simonb SET(ch->ch_rx_flags, RX_TTY_OVERFLOWED); 1276 1.1 simonb } 1277 1.1 simonb break; 1278 1.1 simonb } 1279 1.1 simonb get += 2; 1280 1.1 simonb if (get >= end) 1281 1.1 simonb get = ch->ch_rbuf; 1282 1.1 simonb cc--; 1283 1.1 simonb } 1284 1.1 simonb 1285 1.1 simonb if (cc != scc) { 1286 1.1 simonb ch->ch_rbget = get; 1287 1.1 simonb s = splserial(); 1288 1.1 simonb cc = ch->ch_rbavail += scc - cc; 1289 1.1 simonb /* Buffers should be ok again, release possible block. */ 1290 1.1 simonb if (cc >= ch->ch_r_lowat) { 1291 1.1 simonb if (ISSET(ch->ch_rx_flags, RX_IBUF_OVERFLOWED)) { 1292 1.1 simonb CLR(ch->ch_rx_flags, RX_IBUF_OVERFLOWED); 1293 1.1 simonb SET(ch->ch_imr, 0x02); 1294 1.1 simonb } 1295 1.1 simonb if (ISSET(ch->ch_rx_flags, RX_IBUF_BLOCKED)) { 1296 1.1 simonb CLR(ch->ch_rx_flags, RX_IBUF_BLOCKED); 1297 1.1 simonb sbjcn_dohwiflow(ch); 1298 1.1 simonb } 1299 1.1 simonb } 1300 1.1 simonb splx(s); 1301 1.1 simonb } 1302 1.1 simonb } 1303 1.1 simonb 1304 1.1 simonb integrate void 1305 1.1 simonb sbjcn_txsoft(struct sbjcn_channel *ch, struct tty *tp) 1306 1.1 simonb { 1307 1.1 simonb 1308 1.1 simonb CLR(tp->t_state, TS_BUSY); 1309 1.1 simonb if (ISSET(tp->t_state, TS_FLUSH)) 1310 1.1 simonb CLR(tp->t_state, TS_FLUSH); 1311 1.1 simonb else 1312 1.1 simonb ndflush(&tp->t_outq, (int)(ch->ch_tba - tp->t_outq.c_cf)); 1313 1.1 simonb (*tp->t_linesw->l_start)(tp); 1314 1.1 simonb } 1315 1.1 simonb 1316 1.1 simonb integrate void 1317 1.1 simonb sbjcn_stsoft(struct sbjcn_channel *ch, struct tty *tp) 1318 1.1 simonb { 1319 1.1 simonb u_char iports, delta; 1320 1.1 simonb int s; 1321 1.1 simonb 1322 1.1 simonb s = splserial(); 1323 1.1 simonb iports = ch->ch_iports; 1324 1.1 simonb delta = ch->ch_iports_delta; 1325 1.1 simonb ch->ch_iports_delta = 0; 1326 1.1 simonb splx(s); 1327 1.1 simonb 1328 1.1 simonb if (ISSET(delta, ch->ch_i_dcd)) { 1329 1.1 simonb /* 1330 1.1 simonb * Inform the tty layer that carrier detect changed. 1331 1.1 simonb */ 1332 1.1 simonb (void) (*tp->t_linesw->l_modem)(tp, 1333 1.1 simonb ISSET(iports, ch->ch_i_dcd)); 1334 1.1 simonb } 1335 1.1 simonb 1336 1.1 simonb if (ISSET(delta, ch->ch_i_cts)) { 1337 1.1 simonb /* Block or unblock output according to flow control. */ 1338 1.1 simonb if (ISSET(iports, ch->ch_i_cts)) { 1339 1.1 simonb ch->ch_tx_stopped = 0; 1340 1.1 simonb (*tp->t_linesw->l_start)(tp); 1341 1.1 simonb } else { 1342 1.1 simonb ch->ch_tx_stopped = 1; 1343 1.1 simonb } 1344 1.1 simonb } 1345 1.1 simonb 1346 1.1 simonb #ifdef SBJCN_DEBUG 1347 1.1 simonb if (sbjcn_debug) 1348 1.1 simonb sbjcn_status(ch, "sbjcn_stsoft"); 1349 1.1 simonb #endif 1350 1.1 simonb } 1351 1.1 simonb 1352 1.1 simonb integrate void 1353 1.1 simonb sbjcn_recv(struct sbjcn_channel *ch) 1354 1.1 simonb { 1355 1.1 simonb u_char *put, *end; 1356 1.1 simonb u_int cc; 1357 1.1 simonb 1358 1.1 simonb end = ch->ch_ebuf; 1359 1.1 simonb put = ch->ch_rbput; 1360 1.1 simonb cc = ch->ch_rbavail; 1361 1.1 simonb 1362 1.1 simonb /* XXX process break */ 1363 1.1 simonb 1364 1.1 simonb sbjcncn_grabdword(ch); 1365 1.1 simonb if (ch->ch_waiting_input) { 1366 1.1 simonb if (!ISSET(ch->ch_rx_flags, RX_IBUF_OVERFLOWED)) { 1367 1.1 simonb while (cc > 0) { 1368 1.1 simonb put[0] = sbjcncn_nextbyte(ch); 1369 1.1 simonb put[1] = 1; /* XXXKW ? */ 1370 1.1 simonb put += 2; 1371 1.1 simonb if (put >= end) 1372 1.1 simonb put = ch->ch_rbuf; 1373 1.1 simonb cc--; 1374 1.1 simonb 1375 1.1 simonb if (!ch->ch_waiting_input) 1376 1.1 simonb break; 1377 1.1 simonb } 1378 1.1 simonb 1379 1.1 simonb /* 1380 1.1 simonb * Current string of incoming characters ended 1381 1.1 simonb * because no more data was available or we 1382 1.1 simonb * ran out of space. Schedule a receive event 1383 1.1 simonb * if any data was received. If we're out of 1384 1.1 simonb * space, turn off receive interrupts. 1385 1.1 simonb */ 1386 1.1 simonb ch->ch_rbput = put; 1387 1.1 simonb ch->ch_rbavail = cc; 1388 1.1 simonb if (!ISSET(ch->ch_rx_flags, RX_TTY_OVERFLOWED)) 1389 1.1 simonb ch->ch_rx_ready = 1; 1390 1.1 simonb 1391 1.1 simonb /* 1392 1.1 simonb * See if we are in danger of overflowing a 1393 1.1 simonb * buffer. If so, use hardware flow control 1394 1.1 simonb * to ease the pressure. 1395 1.1 simonb */ 1396 1.1 simonb if (!ISSET(ch->ch_rx_flags, RX_IBUF_BLOCKED) && 1397 1.1 simonb cc < ch->ch_r_hiwat) { 1398 1.1 simonb SET(ch->ch_rx_flags, RX_IBUF_BLOCKED); 1399 1.1 simonb sbjcn_dohwiflow(ch); 1400 1.1 simonb } 1401 1.1 simonb 1402 1.1 simonb /* 1403 1.1 simonb * If we're out of space, disable receive 1404 1.1 simonb * interrupts until the queue has drained 1405 1.1 simonb * a bit. 1406 1.1 simonb */ 1407 1.1 simonb if (!cc) { 1408 1.1 simonb SET(ch->ch_rx_flags, 1409 1.1 simonb RX_IBUF_OVERFLOWED); 1410 1.1 simonb CLR(ch->ch_imr, 0x02); 1411 1.1 simonb } 1412 1.1 simonb } else { 1413 1.1 simonb /* XXX panic? */ 1414 1.1 simonb CLR(ch->ch_imr, 0x02); 1415 1.1 simonb // continue; 1416 1.1 simonb } 1417 1.1 simonb } 1418 1.1 simonb 1419 1.1 simonb /* 1420 1.1 simonb * If we've delayed a parameter change, do it now, and restart 1421 1.1 simonb * output. 1422 1.1 simonb */ 1423 1.1 simonb if (ch->ch_heldchange) { 1424 1.1 simonb sbjcn_loadchannelregs(ch); 1425 1.1 simonb ch->ch_heldchange = 0; 1426 1.1 simonb ch->ch_tbc = ch->ch_heldtbc; 1427 1.1 simonb ch->ch_heldtbc = 0; 1428 1.1 simonb } 1429 1.1 simonb } 1430 1.1 simonb 1431 1.1 simonb void 1432 1.1 simonb sbjcn_callout(void *arg) 1433 1.1 simonb { 1434 1.1 simonb struct sbjcn_channel *ch = arg; 1435 1.1 simonb struct tty *tp = ch->ch_tty; 1436 1.1 simonb 1437 1.1 simonb /* XXX get stuff */ 1438 1.1 simonb sbjcn_recv(ch); 1439 1.1 simonb 1440 1.1 simonb /* XXX check receive */ 1441 1.1 simonb if (ch->ch_rx_ready) { 1442 1.1 simonb ch->ch_rx_ready = 0; 1443 1.1 simonb sbjcn_rxsoft(ch, tp); 1444 1.1 simonb } 1445 1.1 simonb 1446 1.1 simonb /* XXX check transmit */ 1447 1.1 simonb if (ch->ch_tx_done) { 1448 1.1 simonb ch->ch_tx_done = 0; 1449 1.1 simonb sbjcn_txsoft(ch, tp); 1450 1.1 simonb } 1451 1.1 simonb 1452 1.1 simonb callout_reset(&ch->ch_callout, hz/10, sbjcn_callout, ch); 1453 1.1 simonb } 1454 1.1 simonb 1455 1.1 simonb static char sbjcncn_nextbyte(struct sbjcn_channel *ch) 1456 1.1 simonb { 1457 1.1 simonb char c; 1458 1.1 simonb 1459 1.1 simonb sbjcncn_grabdword(ch); 1460 1.1 simonb c = (ch->ch_input_buf >> 56) & 0xff; 1461 1.1 simonb ch->ch_input_buf <<= 8; 1462 1.1 simonb ch->ch_waiting_input--; 1463 1.1 simonb return c; 1464 1.1 simonb } 1465 1.1 simonb 1466 1.1 simonb static void sbjcncn_grabdword(struct sbjcn_channel *ch) 1467 1.1 simonb { 1468 1.1 simonb uint64_t inbuf; 1469 1.1 simonb 1470 1.1 simonb if (ch->ch_waiting_input) 1471 1.1 simonb return; 1472 1.1 simonb 1473 1.1 simonb inbuf = READ_REG(ch->ch_input_reg); 1474 1.1 simonb ch->ch_waiting_input = jtag_input_len(inbuf); 1475 1.1 simonb ch->ch_input_buf = inbuf << 8; 1476 1.1 simonb } 1477 1.1 simonb 1478 1.1 simonb /* 1479 1.1 simonb * Initialize UART for use as console or KGDB line. 1480 1.1 simonb */ 1481 1.1 simonb int 1482 1.1 simonb sbjcn_init(u_long addr, int chan, int rate, tcflag_t cflag) 1483 1.1 simonb { 1484 1.1 simonb /* XXXKW Anything to do here? */ 1485 1.1 simonb return (0); 1486 1.1 simonb } 1487 1.1 simonb 1488 1.1 simonb /* 1489 1.1 simonb * Following are all routines needed for sbjcn to act as console 1490 1.1 simonb */ 1491 1.1 simonb int 1492 1.1 simonb sbjcn_cnattach(u_long addr, int chan, int rate, tcflag_t cflag) 1493 1.1 simonb { 1494 1.1 simonb int res; 1495 1.1 simonb uint64_t ctrl_val; 1496 1.1 simonb static struct consdev sbjcn_cons = { 1497 1.1 simonb NULL, NULL, sbjcn_cngetc, sbjcn_cnputc, sbjcn_cnpollc, NULL, 1498 1.1 simonb NODEV, CN_NORMAL 1499 1.1 simonb }; 1500 1.1 simonb 1501 1.1 simonb res = sbjcn_init(addr, chan, rate, cflag); 1502 1.1 simonb if (res) 1503 1.1 simonb return (res); 1504 1.1 simonb 1505 1.1 simonb cn_tab = &sbjcn_cons; 1506 1.1 simonb 1507 1.1 simonb sbjcn_cons_present = 1; 1508 1.1 simonb sbjcn_cons_addr = addr; 1509 1.1 simonb sbjcn_cons_waiting_input = 0; 1510 1.1 simonb sbjcn_cons_chan = chan; 1511 1.1 simonb sbjcn_cons_rate = rate; 1512 1.1 simonb sbjcn_cons_cflag = cflag; 1513 1.1 simonb 1514 1.1 simonb /* Wait for sign of life from the other end */ 1515 1.1 simonb while ((ctrl_val = READ_REG(MIPS_PHYS_TO_KSEG1(sbjcn_cons_addr + JTAG_CONS_CONTROL))) == 0) 1516 1.1 simonb ; 1517 1.1 simonb 1518 1.1 simonb return (ctrl_val != JTAG_CONS_MAGICNUM); 1519 1.1 simonb } 1520 1.1 simonb 1521 1.1 simonb int 1522 1.1 simonb sbjcn_cngetc(dev_t dev) 1523 1.1 simonb { 1524 1.1 simonb char c; 1525 1.1 simonb 1526 1.1 simonb while (sbjcn_cons_waiting_input == 0) 1527 1.1 simonb sbjcn_cngrabdword(); 1528 1.1 simonb 1529 1.1 simonb c = (sbjcn_cons_input_buf >> 56) & 0xff; 1530 1.1 simonb sbjcn_cons_input_buf <<= 8; 1531 1.1 simonb sbjcn_cons_waiting_input--; 1532 1.1 simonb 1533 1.1 simonb return c; 1534 1.1 simonb } 1535 1.1 simonb 1536 1.1 simonb /* 1537 1.1 simonb * Console kernel output character routine. 1538 1.1 simonb */ 1539 1.1 simonb void 1540 1.1 simonb sbjcn_cnputc(dev_t dev, int c) 1541 1.1 simonb { 1542 1.1 simonb uint64_t outbuf; 1543 1.1 simonb 1544 1.1 simonb outbuf = (1LL << 56) | (((uint64_t)c) << 48); 1545 1.1 simonb WRITE_REG(MIPS_PHYS_TO_KSEG1(sbjcn_cons_addr + JTAG_CONS_OUTPUT), outbuf); 1546 1.1 simonb } 1547 1.1 simonb 1548 1.1 simonb void 1549 1.1 simonb sbjcn_cnpollc(dev_t dev, int on) 1550 1.1 simonb { 1551 1.1 simonb 1552 1.1 simonb } 1553 1.1 simonb 1554 1.1 simonb static void sbjcn_cngrabdword(void) 1555 1.1 simonb { 1556 1.1 simonb uint64_t inbuf; 1557 1.1 simonb 1558 1.1 simonb if (sbjcn_cons_waiting_input) 1559 1.1 simonb return; 1560 1.1 simonb 1561 1.1 simonb inbuf = READ_REG(MIPS_PHYS_TO_KSEG1(sbjcn_cons_addr + JTAG_CONS_INPUT)); 1562 1.1 simonb sbjcn_cons_waiting_input = jtag_input_len(inbuf); 1563 1.1 simonb sbjcn_cons_input_buf = inbuf << 8; 1564 1.1 simonb } 1565 1.1 simonb 1566 1.1 simonb #ifdef KGDB 1567 1.1 simonb int 1568 1.1 simonb sbjcn_kgdb_attach(u_long addr, int chan, int rate, tcflag_t cflag) 1569 1.1 simonb { 1570 1.1 simonb int res; 1571 1.1 simonb 1572 1.1 simonb if (!sbjcn_cons_present && 1573 1.1 simonb sbjcn_cons_addr == addr && sbjcn_cons_chan == chan) 1574 1.1 simonb return (EBUSY); /* cannot share with console */ 1575 1.1 simonb 1576 1.1 simonb res = sbjcn_init(addr, chan, rate, cflag); 1577 1.1 simonb if (res) 1578 1.1 simonb return (res); 1579 1.1 simonb 1580 1.1 simonb kgdb_attach(sbjcn_kgdb_getc, sbjcn_kgdb_putc, NULL); 1581 1.1 simonb kgdb_dev = 123; /* unneeded, only to satisfy some tests */ 1582 1.1 simonb kgdb_rate = rate; 1583 1.1 simonb 1584 1.1 simonb sbjcn_kgdb_present = 1; 1585 1.1 simonb /* XXX sbjcn_init wants addr, but we need the offset addr */ 1586 1.1 simonb sbjcn_kgdb_addr = addr + (chan * 0x100); 1587 1.1 simonb sbjcn_kgdb_chan = chan; 1588 1.1 simonb 1589 1.1 simonb return (0); 1590 1.1 simonb } 1591 1.1 simonb 1592 1.1 simonb /* ARGSUSED */ 1593 1.1 simonb int 1594 1.22 dsl sbjcn_kgdb_getc(void *arg) 1595 1.1 simonb { 1596 1.1 simonb 1597 1.1 simonb return (sbjcn_common_getc(sbjcn_kgdb_addr, sbjcn_kgdb_chan)); 1598 1.1 simonb } 1599 1.1 simonb 1600 1.1 simonb /* ARGSUSED */ 1601 1.1 simonb void 1602 1.22 dsl sbjcn_kgdb_putc(void *arg, int c) 1603 1.1 simonb { 1604 1.1 simonb 1605 1.1 simonb sbjcn_common_putc(sbjcn_kgdb_addr, sbjcn_kgdb_chan, c); 1606 1.1 simonb } 1607 1.1 simonb #endif /* KGDB */ 1608 1.1 simonb 1609 1.1 simonb /* 1610 1.1 simonb * helper function to identify the sbjcn channels used by 1611 1.1 simonb * console or KGDB (and not yet autoconf attached) 1612 1.1 simonb */ 1613 1.1 simonb int 1614 1.1 simonb sbjcn_is_console(u_long addr, int chan) 1615 1.1 simonb { 1616 1.1 simonb 1617 1.1 simonb if (sbjcn_cons_present && !sbjcn_cons_attached && 1618 1.1 simonb sbjcn_cons_addr == addr && sbjcn_cons_chan == chan) 1619 1.1 simonb return (1); 1620 1.1 simonb #ifdef KGDB 1621 1.1 simonb if (sbjcn_kgdb_present && !sbjcn_kgdb_attached && 1622 1.1 simonb sbjcn_kgdb_addr == addr && sbjcn_kgdb_chan == chan) 1623 1.1 simonb return (1); 1624 1.1 simonb #endif 1625 1.1 simonb return (0); 1626 1.1 simonb } 1627