1 1.66 andvar /* $NetBSD: cz.c,v 1.66 2024/02/09 22:08:35 andvar Exp $ */ 2 1.1 thorpej 3 1.1 thorpej /*- 4 1.1 thorpej * Copyright (c) 2000 Zembu Labs, Inc. 5 1.1 thorpej * All rights reserved. 6 1.1 thorpej * 7 1.1 thorpej * Authors: Jason R. Thorpe <thorpej (at) zembu.com> 8 1.1 thorpej * Bill Studenmund <wrstuden (at) zembu.com> 9 1.1 thorpej * 10 1.1 thorpej * Redistribution and use in source and binary forms, with or without 11 1.1 thorpej * modification, are permitted provided that the following conditions 12 1.1 thorpej * are met: 13 1.1 thorpej * 1. Redistributions of source code must retain the above copyright 14 1.1 thorpej * notice, this list of conditions and the following disclaimer. 15 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 thorpej * notice, this list of conditions and the following disclaimer in the 17 1.1 thorpej * documentation and/or other materials provided with the distribution. 18 1.1 thorpej * 3. All advertising materials mentioning features or use of this software 19 1.1 thorpej * must display the following acknowledgement: 20 1.1 thorpej * This product includes software developed by Zembu Labs, Inc. 21 1.1 thorpej * 4. Neither the name of Zembu Labs nor the names of its employees may 22 1.1 thorpej * be used to endorse or promote products derived from this software 23 1.1 thorpej * without specific prior written permission. 24 1.1 thorpej * 25 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY ZEMBU LABS, INC. ``AS IS'' AND ANY EXPRESS 26 1.1 thorpej * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WAR- 27 1.1 thorpej * RANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DIS- 28 1.1 thorpej * CLAIMED. IN NO EVENT SHALL ZEMBU LABS BE LIABLE FOR ANY DIRECT, INDIRECT, 29 1.1 thorpej * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 30 1.1 thorpej * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 31 1.1 thorpej * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 32 1.1 thorpej * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 1.1 thorpej * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34 1.1 thorpej * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 1.1 thorpej */ 36 1.1 thorpej 37 1.1 thorpej /* 38 1.1 thorpej * Cyclades-Z series multi-port serial adapter driver for NetBSD. 39 1.1 thorpej * 40 1.1 thorpej * Some notes: 41 1.1 thorpej * 42 1.1 thorpej * - The Cyclades-Z has fully automatic hardware (and software!) 43 1.26 perry * flow control. We only use RTS/CTS flow control here, 44 1.1 thorpej * and it is implemented in a very simplistic manner. This 45 1.1 thorpej * may be an area of future work. 46 1.1 thorpej * 47 1.1 thorpej * - The PLX can map the either the board's RAM or host RAM 48 1.1 thorpej * into the MIPS's memory window. This would enable us to 49 1.1 thorpej * use less expensive (for us) memory reads/writes to host 50 1.1 thorpej * RAM, rather than time-consuming reads/writes to PCI 51 1.1 thorpej * memory space. However, the PLX can only map a 0-128M 52 1.1 thorpej * window, so we would have to ensure that the DMA address 53 1.1 thorpej * of the host RAM fits there. This is kind of a pain, 54 1.1 thorpej * so we just don't bother right now. 55 1.1 thorpej * 56 1.1 thorpej * - In a perfect world, we would use the autoconfiguration 57 1.1 thorpej * mechanism to attach the TTYs that we find. However, 58 1.1 thorpej * that leads to somewhat icky looking autoconfiguration 59 1.1 thorpej * messages (one for every TTY, up to 64 per board!). So 60 1.1 thorpej * we don't do it that way, but assign minors as if there 61 1.1 thorpej * were the max of 64 ports per board. 62 1.1 thorpej * 63 1.1 thorpej * - We don't bother with PPS support here. There are so many 64 1.1 thorpej * ports, each with a large amount of buffer space, that the 65 1.1 thorpej * normal mode of operation is to poll the boards regularly 66 1.1 thorpej * (generally, every 20ms or so). This makes this driver 67 1.1 thorpej * unsuitable for PPS, as the latency will be generally too 68 1.1 thorpej * high. 69 1.1 thorpej */ 70 1.6 thorpej /* 71 1.6 thorpej * This driver inspired by the FreeBSD driver written by Brian J. McGovern 72 1.6 thorpej * for FreeBSD 3.2. 73 1.6 thorpej */ 74 1.17 lukem 75 1.17 lukem #include <sys/cdefs.h> 76 1.66 andvar __KERNEL_RCSID(0, "$NetBSD: cz.c,v 1.66 2024/02/09 22:08:35 andvar Exp $"); 77 1.1 thorpej 78 1.1 thorpej #include <sys/param.h> 79 1.1 thorpej #include <sys/systm.h> 80 1.1 thorpej #include <sys/proc.h> 81 1.1 thorpej #include <sys/device.h> 82 1.1 thorpej #include <sys/malloc.h> 83 1.1 thorpej #include <sys/tty.h> 84 1.1 thorpej #include <sys/conf.h> 85 1.1 thorpej #include <sys/time.h> 86 1.1 thorpej #include <sys/kernel.h> 87 1.1 thorpej #include <sys/fcntl.h> 88 1.1 thorpej #include <sys/syslog.h> 89 1.37 elad #include <sys/kauth.h> 90 1.1 thorpej 91 1.1 thorpej #include <sys/callout.h> 92 1.1 thorpej 93 1.1 thorpej #include <dev/pci/pcireg.h> 94 1.1 thorpej #include <dev/pci/pcivar.h> 95 1.1 thorpej #include <dev/pci/pcidevs.h> 96 1.1 thorpej #include <dev/pci/czreg.h> 97 1.1 thorpej 98 1.1 thorpej #include <dev/pci/plx9060reg.h> 99 1.1 thorpej #include <dev/pci/plx9060var.h> 100 1.1 thorpej 101 1.1 thorpej #include <dev/microcode/cyclades-z/cyzfirm.h> 102 1.1 thorpej 103 1.1 thorpej #define CZ_DRIVER_VERSION 0x20000411 104 1.1 thorpej 105 1.1 thorpej #define CZ_POLL_MS 20 106 1.1 thorpej 107 1.1 thorpej /* These are the interrupts we always use. */ 108 1.1 thorpej #define CZ_INTERRUPTS \ 109 1.1 thorpej (C_IN_MDSR | C_IN_MRI | C_IN_MRTS | C_IN_MCTS | C_IN_TXBEMPTY | \ 110 1.1 thorpej C_IN_TXFEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM | C_IN_RXNNDT | \ 111 1.1 thorpej C_IN_MDCD | C_IN_PR_ERROR | C_IN_FR_ERROR | C_IN_OVR_ERROR | \ 112 1.4 thorpej C_IN_RXOFL | C_IN_IOCTLW | C_IN_RXBRK) 113 1.1 thorpej 114 1.1 thorpej /* 115 1.1 thorpej * cztty_softc: 116 1.1 thorpej * 117 1.1 thorpej * Per-channel (TTY) state. 118 1.1 thorpej */ 119 1.1 thorpej struct cztty_softc { 120 1.1 thorpej struct cz_softc *sc_parent; 121 1.1 thorpej struct tty *sc_tty; 122 1.1 thorpej 123 1.45 ad callout_t sc_diag_ch; 124 1.1 thorpej 125 1.1 thorpej int sc_channel; /* Also used to flag unattached chan */ 126 1.1 thorpej #define CZTTY_CHANNEL_DEAD -1 127 1.1 thorpej 128 1.1 thorpej bus_space_tag_t sc_chan_st; /* channel space tag */ 129 1.1 thorpej bus_space_handle_t sc_chan_sh; /* channel space handle */ 130 1.1 thorpej bus_space_handle_t sc_buf_sh; /* buffer space handle */ 131 1.1 thorpej 132 1.1 thorpej u_int sc_overflows, 133 1.1 thorpej sc_parity_errors, 134 1.1 thorpej sc_framing_errors, 135 1.1 thorpej sc_errors; 136 1.1 thorpej 137 1.1 thorpej int sc_swflags; 138 1.1 thorpej 139 1.1 thorpej u_int32_t sc_rs_control_dtr, 140 1.1 thorpej sc_chanctl_hw_flow, 141 1.1 thorpej sc_chanctl_comm_baud, 142 1.1 thorpej sc_chanctl_rs_control, 143 1.1 thorpej sc_chanctl_comm_data_l, 144 1.1 thorpej sc_chanctl_comm_parity; 145 1.1 thorpej }; 146 1.1 thorpej 147 1.1 thorpej /* 148 1.1 thorpej * cz_softc: 149 1.1 thorpej * 150 1.1 thorpej * Per-board state. 151 1.1 thorpej */ 152 1.1 thorpej struct cz_softc { 153 1.56 chs device_t cz_dev; /* generic device info */ 154 1.1 thorpej struct plx9060_config cz_plx; /* PLX 9060 config info */ 155 1.1 thorpej bus_space_tag_t cz_win_st; /* window space tag */ 156 1.1 thorpej bus_space_handle_t cz_win_sh; /* window space handle */ 157 1.45 ad callout_t cz_callout; /* callout for polling-mode */ 158 1.1 thorpej 159 1.1 thorpej void *cz_ih; /* interrupt handle */ 160 1.1 thorpej 161 1.1 thorpej u_int32_t cz_mailbox0; /* our MAILBOX0 value */ 162 1.1 thorpej int cz_nchannels; /* number of channels */ 163 1.1 thorpej int cz_nopenchan; /* number of open channels */ 164 1.1 thorpej struct cztty_softc *cz_ports; /* our array of ports */ 165 1.1 thorpej 166 1.1 thorpej bus_addr_t cz_fwctl; /* offset of firmware control */ 167 1.1 thorpej }; 168 1.1 thorpej 169 1.32 thorpej static int cz_wait_pci_doorbell(struct cz_softc *, const char *); 170 1.1 thorpej 171 1.32 thorpej static int cz_load_firmware(struct cz_softc *); 172 1.1 thorpej 173 1.32 thorpej static int cz_intr(void *); 174 1.32 thorpej static void cz_poll(void *); 175 1.32 thorpej static int cztty_transmit(struct cztty_softc *, struct tty *); 176 1.32 thorpej static int cztty_receive(struct cztty_softc *, struct tty *); 177 1.32 thorpej 178 1.32 thorpej static struct cztty_softc *cztty_getttysoftc(dev_t dev); 179 1.32 thorpej static int cztty_attached_ttys; 180 1.32 thorpej static int cz_timeout_ticks; 181 1.32 thorpej 182 1.32 thorpej static void czttystart(struct tty *tp); 183 1.32 thorpej static int czttyparam(struct tty *tp, struct termios *t); 184 1.32 thorpej static void cztty_shutdown(struct cztty_softc *sc); 185 1.32 thorpej static void cztty_modem(struct cztty_softc *sc, int onoff); 186 1.32 thorpej static void cztty_break(struct cztty_softc *sc, int onoff); 187 1.32 thorpej static void tiocm_to_cztty(struct cztty_softc *sc, u_long how, int ttybits); 188 1.32 thorpej static int cztty_to_tiocm(struct cztty_softc *sc); 189 1.32 thorpej static void cztty_diag(void *arg); 190 1.1 thorpej 191 1.1 thorpej extern struct cfdriver cz_cd; 192 1.1 thorpej 193 1.1 thorpej /* 194 1.1 thorpej * Macros to read and write the PLX. 195 1.1 thorpej */ 196 1.1 thorpej #define CZ_PLX_READ(cz, reg) \ 197 1.1 thorpej bus_space_read_4((cz)->cz_plx.plx_st, (cz)->cz_plx.plx_sh, (reg)) 198 1.1 thorpej #define CZ_PLX_WRITE(cz, reg, val) \ 199 1.1 thorpej bus_space_write_4((cz)->cz_plx.plx_st, (cz)->cz_plx.plx_sh, \ 200 1.1 thorpej (reg), (val)) 201 1.1 thorpej 202 1.1 thorpej /* 203 1.1 thorpej * Macros to read and write the FPGA. We must already be in the FPGA 204 1.1 thorpej * window for this. 205 1.1 thorpej */ 206 1.1 thorpej #define CZ_FPGA_READ(cz, reg) \ 207 1.1 thorpej bus_space_read_4((cz)->cz_win_st, (cz)->cz_win_sh, (reg)) 208 1.1 thorpej #define CZ_FPGA_WRITE(cz, reg, val) \ 209 1.1 thorpej bus_space_write_4((cz)->cz_win_st, (cz)->cz_win_sh, (reg), (val)) 210 1.1 thorpej 211 1.1 thorpej /* 212 1.1 thorpej * Macros to read and write the firmware control structures in board RAM. 213 1.1 thorpej */ 214 1.1 thorpej #define CZ_FWCTL_READ(cz, off) \ 215 1.1 thorpej bus_space_read_4((cz)->cz_win_st, (cz)->cz_win_sh, \ 216 1.1 thorpej (cz)->cz_fwctl + (off)) 217 1.1 thorpej 218 1.1 thorpej #define CZ_FWCTL_WRITE(cz, off, val) \ 219 1.1 thorpej bus_space_write_4((cz)->cz_win_st, (cz)->cz_win_sh, \ 220 1.1 thorpej (cz)->cz_fwctl + (off), (val)) 221 1.1 thorpej 222 1.1 thorpej /* 223 1.1 thorpej * Convenience macros for cztty routines. PLX window MUST be to RAM. 224 1.1 thorpej */ 225 1.1 thorpej #define CZTTY_CHAN_READ(sc, off) \ 226 1.1 thorpej bus_space_read_4((sc)->sc_chan_st, (sc)->sc_chan_sh, (off)) 227 1.1 thorpej 228 1.1 thorpej #define CZTTY_CHAN_WRITE(sc, off, val) \ 229 1.1 thorpej bus_space_write_4((sc)->sc_chan_st, (sc)->sc_chan_sh, \ 230 1.1 thorpej (off), (val)) 231 1.1 thorpej 232 1.1 thorpej #define CZTTY_BUF_READ(sc, off) \ 233 1.1 thorpej bus_space_read_4((sc)->sc_chan_st, (sc)->sc_buf_sh, (off)) 234 1.1 thorpej 235 1.1 thorpej #define CZTTY_BUF_WRITE(sc, off, val) \ 236 1.1 thorpej bus_space_write_4((sc)->sc_chan_st, (sc)->sc_buf_sh, \ 237 1.1 thorpej (off), (val)) 238 1.1 thorpej 239 1.1 thorpej /* 240 1.1 thorpej * Convenience macros. 241 1.1 thorpej */ 242 1.1 thorpej #define CZ_WIN_RAM(cz) \ 243 1.1 thorpej do { \ 244 1.1 thorpej CZ_PLX_WRITE((cz), PLX_LAS0BA, LOCAL_ADDR0_RAM); \ 245 1.1 thorpej delay(100); \ 246 1.1 thorpej } while (0) 247 1.1 thorpej 248 1.1 thorpej #define CZ_WIN_FPGA(cz) \ 249 1.1 thorpej do { \ 250 1.1 thorpej CZ_PLX_WRITE((cz), PLX_LAS0BA, LOCAL_ADDR0_FPGA); \ 251 1.1 thorpej delay(100); \ 252 1.1 thorpej } while (0) 253 1.1 thorpej 254 1.1 thorpej /***************************************************************************** 255 1.1 thorpej * Cyclades-Z controller code starts here... 256 1.1 thorpej *****************************************************************************/ 257 1.1 thorpej 258 1.1 thorpej /* 259 1.1 thorpej * cz_match: 260 1.1 thorpej * 261 1.1 thorpej * Determine if the given PCI device is a Cyclades-Z board. 262 1.1 thorpej */ 263 1.32 thorpej static int 264 1.51 cegger cz_match(device_t parent, cfdata_t match, void *aux) 265 1.1 thorpej { 266 1.1 thorpej struct pci_attach_args *pa = aux; 267 1.1 thorpej 268 1.1 thorpej if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_CYCLADES) { 269 1.1 thorpej switch (PCI_PRODUCT(pa->pa_id)) { 270 1.1 thorpej case PCI_PRODUCT_CYCLADES_CYCLOMZ_2: 271 1.1 thorpej return (1); 272 1.1 thorpej } 273 1.1 thorpej } 274 1.1 thorpej 275 1.1 thorpej return (0); 276 1.1 thorpej } 277 1.1 thorpej 278 1.1 thorpej /* 279 1.1 thorpej * cz_attach: 280 1.1 thorpej * 281 1.1 thorpej * A Cyclades-Z board was found; attach it. 282 1.1 thorpej */ 283 1.32 thorpej static void 284 1.51 cegger cz_attach(device_t parent, device_t self, void *aux) 285 1.1 thorpej { 286 1.32 thorpej extern const struct cdevsw cz_cdevsw; /* XXX */ 287 1.52 cegger struct cz_softc *cz = device_private(self); 288 1.1 thorpej struct pci_attach_args *pa = aux; 289 1.1 thorpej pci_intr_handle_t ih; 290 1.1 thorpej const char *intrstr = NULL; 291 1.1 thorpej struct cztty_softc *sc; 292 1.1 thorpej struct tty *tp; 293 1.1 thorpej int i; 294 1.59 christos char intrbuf[PCI_INTRSTR_LEN]; 295 1.1 thorpej 296 1.25 thorpej aprint_naive(": Multi-port serial controller\n"); 297 1.25 thorpej aprint_normal(": Cyclades-Z multiport serial\n"); 298 1.1 thorpej 299 1.56 chs cz->cz_dev = self; 300 1.1 thorpej cz->cz_plx.plx_pc = pa->pa_pc; 301 1.1 thorpej cz->cz_plx.plx_tag = pa->pa_tag; 302 1.1 thorpej 303 1.1 thorpej if (pci_mapreg_map(pa, PLX_PCI_RUNTIME_MEMADDR, 304 1.1 thorpej PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT, 0, 305 1.1 thorpej &cz->cz_plx.plx_st, &cz->cz_plx.plx_sh, NULL, NULL) != 0) { 306 1.56 chs aprint_error_dev(cz->cz_dev, "unable to map PLX registers\n"); 307 1.1 thorpej return; 308 1.1 thorpej } 309 1.1 thorpej if (pci_mapreg_map(pa, PLX_PCI_LOCAL_ADDR0, 310 1.1 thorpej PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT, 0, 311 1.1 thorpej &cz->cz_win_st, &cz->cz_win_sh, NULL, NULL) != 0) { 312 1.56 chs aprint_error_dev(cz->cz_dev, "unable to map device window\n"); 313 1.1 thorpej return; 314 1.1 thorpej } 315 1.1 thorpej 316 1.1 thorpej cz->cz_mailbox0 = CZ_PLX_READ(cz, PLX_MAILBOX0); 317 1.1 thorpej cz->cz_nopenchan = 0; 318 1.1 thorpej 319 1.1 thorpej /* 320 1.1 thorpej * Make sure that the board is completely stopped. 321 1.1 thorpej */ 322 1.1 thorpej CZ_WIN_FPGA(cz); 323 1.1 thorpej CZ_FPGA_WRITE(cz, FPGA_CPU_STOP, 0); 324 1.1 thorpej 325 1.1 thorpej /* 326 1.1 thorpej * Load the board's firmware. 327 1.1 thorpej */ 328 1.1 thorpej if (cz_load_firmware(cz) != 0) 329 1.1 thorpej return; 330 1.1 thorpej 331 1.1 thorpej /* 332 1.1 thorpej * Now that we're ready to roll, map and establish the interrupt 333 1.1 thorpej * handler. 334 1.1 thorpej */ 335 1.12 sommerfe if (pci_intr_map(pa, &ih) != 0) { 336 1.1 thorpej /* 337 1.1 thorpej * The common case is for Cyclades-Z boards to run 338 1.1 thorpej * in polling mode, and thus not have an interrupt 339 1.1 thorpej * mapped for them. Don't bother reporting that 340 1.1 thorpej * the interrupt is not mappable, since this isn't 341 1.1 thorpej * really an error. 342 1.1 thorpej */ 343 1.1 thorpej cz->cz_ih = NULL; 344 1.1 thorpej goto polling_mode; 345 1.1 thorpej } else { 346 1.59 christos intrstr = pci_intr_string(pa->pa_pc, ih, intrbuf, sizeof(intrbuf)); 347 1.64 jdolecek cz->cz_ih = pci_intr_establish_xname(pa->pa_pc, ih, IPL_TTY, 348 1.64 jdolecek cz_intr, cz, device_xname(self)); 349 1.1 thorpej } 350 1.1 thorpej if (cz->cz_ih == NULL) { 351 1.56 chs aprint_error_dev(cz->cz_dev, "unable to establish interrupt"); 352 1.1 thorpej if (intrstr != NULL) 353 1.53 njoly aprint_error(" at %s", intrstr); 354 1.53 njoly aprint_error("\n"); 355 1.1 thorpej /* We will fall-back on polling mode. */ 356 1.1 thorpej } else 357 1.62 msaitoh aprint_normal_dev(cz->cz_dev, "interrupting at %s\n", intrstr); 358 1.1 thorpej 359 1.1 thorpej polling_mode: 360 1.1 thorpej if (cz->cz_ih == NULL) { 361 1.45 ad callout_init(&cz->cz_callout, 0); 362 1.1 thorpej if (cz_timeout_ticks == 0) 363 1.63 riastrad cz_timeout_ticks = uimax(1, hz * CZ_POLL_MS / 1000); 364 1.62 msaitoh aprint_normal_dev(cz->cz_dev, 365 1.62 msaitoh "polling mode, %d ms interval (%d tick%s)\n", CZ_POLL_MS, 366 1.62 msaitoh cz_timeout_ticks, cz_timeout_ticks == 1 ? "" : "s"); 367 1.1 thorpej } 368 1.1 thorpej 369 1.1 thorpej /* 370 1.1 thorpej * Allocate sufficient pointers for the children and 371 1.1 thorpej * attach them. Set all ports to a reasonable initial 372 1.1 thorpej * configuration while we're at it: 373 1.1 thorpej * 374 1.1 thorpej * disabled 375 1.1 thorpej * 8N1 376 1.1 thorpej * default baud rate 377 1.1 thorpej * hardware flow control. 378 1.1 thorpej */ 379 1.1 thorpej CZ_WIN_RAM(cz); 380 1.10 thorpej 381 1.10 thorpej if (cz->cz_nchannels == 0) { 382 1.10 thorpej /* No channels? No more work to do! */ 383 1.10 thorpej return; 384 1.10 thorpej } 385 1.10 thorpej 386 1.1 thorpej cz->cz_ports = malloc(sizeof(struct cztty_softc) * cz->cz_nchannels, 387 1.18 tsutsui M_DEVBUF, M_WAITOK|M_ZERO); 388 1.7 wrstuden cztty_attached_ttys += cz->cz_nchannels; 389 1.1 thorpej 390 1.1 thorpej for (i = 0; i < cz->cz_nchannels; i++) { 391 1.1 thorpej sc = &cz->cz_ports[i]; 392 1.1 thorpej 393 1.1 thorpej sc->sc_channel = i; 394 1.1 thorpej sc->sc_chan_st = cz->cz_win_st; 395 1.1 thorpej sc->sc_parent = cz; 396 1.1 thorpej 397 1.1 thorpej if (bus_space_subregion(cz->cz_win_st, cz->cz_win_sh, 398 1.1 thorpej cz->cz_fwctl + ZFIRM_CHNCTL_OFF(i, 0), 399 1.1 thorpej ZFIRM_CHNCTL_SIZE, &sc->sc_chan_sh)) { 400 1.56 chs aprint_error_dev(cz->cz_dev, 401 1.48 cegger "unable to subregion channel %d control\n", i); 402 1.1 thorpej sc->sc_channel = CZTTY_CHANNEL_DEAD; 403 1.1 thorpej continue; 404 1.1 thorpej } 405 1.1 thorpej if (bus_space_subregion(cz->cz_win_st, cz->cz_win_sh, 406 1.1 thorpej cz->cz_fwctl + ZFIRM_BUFCTL_OFF(i, 0), 407 1.1 thorpej ZFIRM_BUFCTL_SIZE, &sc->sc_buf_sh)) { 408 1.56 chs aprint_error_dev(cz->cz_dev, 409 1.48 cegger "unable to subregion channel %d buffer\n", i); 410 1.1 thorpej sc->sc_channel = CZTTY_CHANNEL_DEAD; 411 1.1 thorpej continue; 412 1.1 thorpej } 413 1.1 thorpej 414 1.45 ad callout_init(&sc->sc_diag_ch, 0); 415 1.1 thorpej 416 1.55 rmind tp = tty_alloc(); 417 1.20 gehenna tp->t_dev = makedev(cdevsw_lookup_major(&cz_cdevsw), 418 1.56 chs (device_unit(cz->cz_dev) * ZFIRM_MAX_CHANNELS) + i); 419 1.1 thorpej tp->t_oproc = czttystart; 420 1.1 thorpej tp->t_param = czttyparam; 421 1.1 thorpej tty_attach(tp); 422 1.1 thorpej 423 1.1 thorpej sc->sc_tty = tp; 424 1.1 thorpej 425 1.1 thorpej CZTTY_CHAN_WRITE(sc, CHNCTL_OP_MODE, C_CH_DISABLE); 426 1.1 thorpej CZTTY_CHAN_WRITE(sc, CHNCTL_INTR_ENABLE, CZ_INTERRUPTS); 427 1.1 thorpej CZTTY_CHAN_WRITE(sc, CHNCTL_SW_FLOW, 0); 428 1.1 thorpej CZTTY_CHAN_WRITE(sc, CHNCTL_FLOW_XON, 0x11); 429 1.1 thorpej CZTTY_CHAN_WRITE(sc, CHNCTL_FLOW_XOFF, 0x13); 430 1.1 thorpej CZTTY_CHAN_WRITE(sc, CHNCTL_COMM_BAUD, TTYDEF_SPEED); 431 1.1 thorpej CZTTY_CHAN_WRITE(sc, CHNCTL_COMM_PARITY, C_PR_NONE); 432 1.1 thorpej CZTTY_CHAN_WRITE(sc, CHNCTL_COMM_DATA_L, C_DL_CS8 | C_DL_1STOP); 433 1.1 thorpej CZTTY_CHAN_WRITE(sc, CHNCTL_COMM_FLAGS, 0); 434 1.1 thorpej CZTTY_CHAN_WRITE(sc, CHNCTL_HW_FLOW, C_RS_CTS | C_RS_RTS); 435 1.1 thorpej CZTTY_CHAN_WRITE(sc, CHNCTL_RS_CONTROL, 0); 436 1.1 thorpej } 437 1.1 thorpej } 438 1.1 thorpej 439 1.56 chs CFATTACH_DECL_NEW(cz, sizeof(struct cz_softc), 440 1.32 thorpej cz_match, cz_attach, NULL, NULL); 441 1.32 thorpej 442 1.32 thorpej #if 0 443 1.1 thorpej /* 444 1.1 thorpej * cz_reset_board: 445 1.1 thorpej * 446 1.1 thorpej * Reset the board via the PLX. 447 1.1 thorpej */ 448 1.32 thorpej static void 449 1.1 thorpej cz_reset_board(struct cz_softc *cz) 450 1.1 thorpej { 451 1.1 thorpej u_int32_t reg; 452 1.1 thorpej 453 1.1 thorpej reg = CZ_PLX_READ(cz, PLX_CONTROL); 454 1.1 thorpej CZ_PLX_WRITE(cz, PLX_CONTROL, reg | CONTROL_SWR); 455 1.1 thorpej delay(1000); 456 1.1 thorpej 457 1.1 thorpej CZ_PLX_WRITE(cz, PLX_CONTROL, reg); 458 1.1 thorpej delay(1000); 459 1.1 thorpej 460 1.1 thorpej /* Now reload the PLX from its EEPROM. */ 461 1.1 thorpej reg = CZ_PLX_READ(cz, PLX_CONTROL); 462 1.1 thorpej CZ_PLX_WRITE(cz, PLX_CONTROL, reg | CONTROL_RELOADCFG); 463 1.1 thorpej delay(1000); 464 1.1 thorpej CZ_PLX_WRITE(cz, PLX_CONTROL, reg); 465 1.1 thorpej } 466 1.32 thorpej #endif 467 1.1 thorpej 468 1.1 thorpej /* 469 1.1 thorpej * cz_load_firmware: 470 1.1 thorpej * 471 1.1 thorpej * Load the ZFIRM firmware into the board's RAM and start it 472 1.1 thorpej * running. 473 1.1 thorpej */ 474 1.32 thorpej static int 475 1.1 thorpej cz_load_firmware(struct cz_softc *cz) 476 1.1 thorpej { 477 1.31 christos const struct zfirm_header *zfh; 478 1.31 christos const struct zfirm_config *zfc; 479 1.31 christos const struct zfirm_block *zfb, *zblocks; 480 1.1 thorpej const u_int8_t *cp; 481 1.1 thorpej const char *board; 482 1.1 thorpej u_int32_t fid; 483 1.1 thorpej int i, j, nconfigs, nblocks, nbytes; 484 1.1 thorpej 485 1.31 christos zfh = (const struct zfirm_header *) cycladesz_firmware; 486 1.1 thorpej 487 1.1 thorpej /* Find the config header. */ 488 1.1 thorpej if (le32toh(zfh->zfh_configoff) & (sizeof(u_int32_t) - 1)) { 489 1.56 chs aprint_error_dev(cz->cz_dev, "bad ZFIRM config offset: 0x%x\n", 490 1.48 cegger le32toh(zfh->zfh_configoff)); 491 1.1 thorpej return (EIO); 492 1.1 thorpej } 493 1.31 christos zfc = (const struct zfirm_config *)(cycladesz_firmware + 494 1.1 thorpej le32toh(zfh->zfh_configoff)); 495 1.1 thorpej nconfigs = le32toh(zfh->zfh_nconfig); 496 1.1 thorpej 497 1.1 thorpej /* Locate the correct configuration for our board. */ 498 1.1 thorpej for (i = 0; i < nconfigs; i++, zfc++) { 499 1.1 thorpej if (le32toh(zfc->zfc_mailbox) == cz->cz_mailbox0 && 500 1.1 thorpej le32toh(zfc->zfc_function) == ZFC_FUNCTION_NORMAL) 501 1.1 thorpej break; 502 1.1 thorpej } 503 1.1 thorpej if (i == nconfigs) { 504 1.56 chs aprint_error_dev(cz->cz_dev, "unable to locate config header\n"); 505 1.1 thorpej return (EIO); 506 1.1 thorpej } 507 1.1 thorpej 508 1.1 thorpej nblocks = le32toh(zfc->zfc_nblocks); 509 1.31 christos zblocks = (const struct zfirm_block *)(cycladesz_firmware + 510 1.1 thorpej le32toh(zfh->zfh_blockoff)); 511 1.1 thorpej 512 1.1 thorpej /* 513 1.1 thorpej * 8Zo ver. 1 doesn't have an FPGA. Load it on all others if 514 1.1 thorpej * necessary. 515 1.1 thorpej */ 516 1.1 thorpej if (cz->cz_mailbox0 != MAILBOX0_8Zo_V1 517 1.1 thorpej #if 0 518 1.1 thorpej && ((CZ_PLX_READ(cz, PLX_CONTROL) & CONTROL_FPGA_LOADED) == 0) 519 1.1 thorpej #endif 520 1.1 thorpej ) { 521 1.1 thorpej #ifdef CZ_DEBUG 522 1.56 chs aprint_debug_dev(cz->cz_dev, "Loading FPGA..."); 523 1.1 thorpej #endif 524 1.1 thorpej CZ_WIN_FPGA(cz); 525 1.1 thorpej for (i = 0; i < nblocks; i++) { 526 1.1 thorpej /* zfb = zblocks + le32toh(zfc->zfc_blocklist[i]) ?? */ 527 1.1 thorpej zfb = &zblocks[le32toh(zfc->zfc_blocklist[i])]; 528 1.7 wrstuden if (le32toh(zfb->zfb_type) == ZFB_TYPE_FPGA) { 529 1.1 thorpej nbytes = le32toh(zfb->zfb_size); 530 1.1 thorpej cp = &cycladesz_firmware[ 531 1.1 thorpej le32toh(zfb->zfb_fileoff)]; 532 1.1 thorpej for (j = 0; j < nbytes; j++, cp++) { 533 1.1 thorpej bus_space_write_1(cz->cz_win_st, 534 1.1 thorpej cz->cz_win_sh, 0, *cp); 535 1.1 thorpej /* FPGA needs 30-100us to settle. */ 536 1.1 thorpej delay(10); 537 1.1 thorpej } 538 1.1 thorpej } 539 1.1 thorpej } 540 1.1 thorpej #ifdef CZ_DEBUG 541 1.25 thorpej aprint_debug("done\n"); 542 1.1 thorpej #endif 543 1.1 thorpej } 544 1.1 thorpej 545 1.1 thorpej /* Now load the firmware. */ 546 1.1 thorpej CZ_WIN_RAM(cz); 547 1.1 thorpej 548 1.1 thorpej for (i = 0; i < nblocks; i++) { 549 1.1 thorpej /* zfb = zblocks + le32toh(zfc->zfc_blocklist[i]) ?? */ 550 1.1 thorpej zfb = &zblocks[le32toh(zfc->zfc_blocklist[i])]; 551 1.1 thorpej if (le32toh(zfb->zfb_type) == ZFB_TYPE_FIRMWARE) { 552 1.1 thorpej const u_int32_t *lp; 553 1.1 thorpej u_int32_t ro = le32toh(zfb->zfb_ramoff); 554 1.1 thorpej nbytes = le32toh(zfb->zfb_size); 555 1.1 thorpej lp = (const u_int32_t *) 556 1.1 thorpej &cycladesz_firmware[le32toh(zfb->zfb_fileoff)]; 557 1.1 thorpej for (j = 0; j < nbytes; j += 4, lp++) { 558 1.1 thorpej bus_space_write_4(cz->cz_win_st, cz->cz_win_sh, 559 1.7 wrstuden ro + j, le32toh(*lp)); 560 1.1 thorpej delay(10); 561 1.1 thorpej } 562 1.1 thorpej } 563 1.1 thorpej } 564 1.1 thorpej 565 1.1 thorpej /* Now restart the MIPS. */ 566 1.1 thorpej CZ_WIN_FPGA(cz); 567 1.1 thorpej CZ_FPGA_WRITE(cz, FPGA_CPU_START, 0); 568 1.1 thorpej 569 1.1 thorpej /* Wait for the MIPS to start, then report the results. */ 570 1.1 thorpej CZ_WIN_RAM(cz); 571 1.1 thorpej 572 1.1 thorpej #ifdef CZ_DEBUG 573 1.56 chs aprint_debug_dev(cz->cz_dev, "waiting for MIPS to start"); 574 1.1 thorpej #endif 575 1.1 thorpej for (i = 0; i < 100; i++) { 576 1.1 thorpej fid = bus_space_read_4(cz->cz_win_st, cz->cz_win_sh, 577 1.1 thorpej ZFIRM_SIG_OFF); 578 1.1 thorpej if (fid == ZFIRM_SIG) { 579 1.1 thorpej /* MIPS has booted. */ 580 1.1 thorpej break; 581 1.1 thorpej } else if (fid == ZFIRM_HLT) { 582 1.1 thorpej /* 583 1.1 thorpej * The MIPS has halted, usually due to a power 584 1.1 thorpej * shortage on the expansion module. 585 1.1 thorpej */ 586 1.56 chs aprint_error_dev(cz->cz_dev, "MIPS halted; possible power supply " 587 1.48 cegger "problem\n"); 588 1.1 thorpej return (EIO); 589 1.1 thorpej } else { 590 1.1 thorpej #ifdef CZ_DEBUG 591 1.1 thorpej if ((i % 8) == 0) 592 1.25 thorpej aprint_debug("."); 593 1.1 thorpej #endif 594 1.1 thorpej delay(250000); 595 1.1 thorpej } 596 1.1 thorpej } 597 1.1 thorpej #ifdef CZ_DEBUG 598 1.25 thorpej aprint_debug("\n"); 599 1.1 thorpej #endif 600 1.1 thorpej if (i == 100) { 601 1.1 thorpej CZ_WIN_FPGA(cz); 602 1.56 chs aprint_error_dev(cz->cz_dev, 603 1.48 cegger "MIPS failed to start; wanted 0x%08x got 0x%08x\n", 604 1.48 cegger ZFIRM_SIG, fid); 605 1.56 chs aprint_error_dev(cz->cz_dev, "FPGA ID 0x%08x, FPGA version 0x%08x\n", 606 1.48 cegger CZ_FPGA_READ(cz, FPGA_ID), 607 1.1 thorpej CZ_FPGA_READ(cz, FPGA_VERSION)); 608 1.1 thorpej return (EIO); 609 1.1 thorpej } 610 1.1 thorpej 611 1.1 thorpej /* 612 1.1 thorpej * Locate the firmware control structures. 613 1.1 thorpej */ 614 1.1 thorpej cz->cz_fwctl = bus_space_read_4(cz->cz_win_st, cz->cz_win_sh, 615 1.1 thorpej ZFIRM_CTRLADDR_OFF); 616 1.1 thorpej #ifdef CZ_DEBUG 617 1.56 chs aprint_debug_dev(cz->cz_dev, "FWCTL structure at offset " 618 1.54 jym "%#08" PRIxPADDR "\n", cz->cz_fwctl); 619 1.1 thorpej #endif 620 1.1 thorpej 621 1.1 thorpej CZ_FWCTL_WRITE(cz, BRDCTL_C_OS, C_OS_BSD); 622 1.1 thorpej CZ_FWCTL_WRITE(cz, BRDCTL_DRVERSION, CZ_DRIVER_VERSION); 623 1.1 thorpej 624 1.1 thorpej cz->cz_nchannels = CZ_FWCTL_READ(cz, BRDCTL_NCHANNEL); 625 1.1 thorpej 626 1.1 thorpej switch (cz->cz_mailbox0) { 627 1.1 thorpej case MAILBOX0_8Zo_V1: 628 1.1 thorpej board = "Cyclades-8Zo ver. 1"; 629 1.1 thorpej break; 630 1.1 thorpej 631 1.1 thorpej case MAILBOX0_8Zo_V2: 632 1.1 thorpej board = "Cyclades-8Zo ver. 2"; 633 1.1 thorpej break; 634 1.1 thorpej 635 1.1 thorpej case MAILBOX0_Ze_V1: 636 1.1 thorpej board = "Cyclades-Ze"; 637 1.1 thorpej break; 638 1.1 thorpej 639 1.1 thorpej default: 640 1.1 thorpej board = "unknown Cyclades Z-series"; 641 1.1 thorpej break; 642 1.1 thorpej } 643 1.1 thorpej 644 1.1 thorpej fid = CZ_FWCTL_READ(cz, BRDCTL_FWVERSION); 645 1.56 chs aprint_normal_dev(cz->cz_dev, "%s, ", board); 646 1.10 thorpej if (cz->cz_nchannels == 0) 647 1.25 thorpej aprint_normal("no channels attached, "); 648 1.10 thorpej else 649 1.25 thorpej aprint_normal("%d channels (ttyCZ%04d..ttyCZ%04d), ", 650 1.10 thorpej cz->cz_nchannels, cztty_attached_ttys, 651 1.10 thorpej cztty_attached_ttys + (cz->cz_nchannels - 1)); 652 1.25 thorpej aprint_normal("firmware %x.%x.%x\n", 653 1.1 thorpej (fid >> 8) & 0xf, (fid >> 4) & 0xf, fid & 0xf); 654 1.1 thorpej 655 1.1 thorpej return (0); 656 1.1 thorpej } 657 1.1 thorpej 658 1.1 thorpej /* 659 1.1 thorpej * cz_poll: 660 1.1 thorpej * 661 1.1 thorpej * This card doesn't do interrupts, so scan it for activity every CZ_POLL_MS 662 1.1 thorpej * ms. 663 1.1 thorpej */ 664 1.32 thorpej static void 665 1.1 thorpej cz_poll(void *arg) 666 1.1 thorpej { 667 1.1 thorpej int s = spltty(); 668 1.1 thorpej struct cz_softc *cz = arg; 669 1.1 thorpej 670 1.1 thorpej cz_intr(cz); 671 1.1 thorpej callout_reset(&cz->cz_callout, cz_timeout_ticks, cz_poll, cz); 672 1.1 thorpej 673 1.1 thorpej splx(s); 674 1.1 thorpej } 675 1.1 thorpej 676 1.1 thorpej /* 677 1.1 thorpej * cz_intr: 678 1.1 thorpej * 679 1.1 thorpej * Interrupt service routine. 680 1.1 thorpej * 681 1.1 thorpej * We either are receiving an interrupt directly from the board, or we are 682 1.1 thorpej * in polling mode and it's time to poll. 683 1.1 thorpej */ 684 1.32 thorpej static int 685 1.1 thorpej cz_intr(void *arg) 686 1.1 thorpej { 687 1.1 thorpej int rval = 0; 688 1.57 martin u_int command, channel; 689 1.1 thorpej struct cz_softc *cz = arg; 690 1.1 thorpej struct cztty_softc *sc; 691 1.1 thorpej struct tty *tp; 692 1.1 thorpej 693 1.1 thorpej while ((command = (CZ_PLX_READ(cz, PLX_LOCAL_PCI_DOORBELL) & 0xff))) { 694 1.1 thorpej rval = 1; 695 1.9 thorpej channel = CZ_FWCTL_READ(cz, BRDCTL_FWCMD_CHANNEL); 696 1.57 martin /* XXX - is this needed? */ 697 1.57 martin (void)CZ_FWCTL_READ(cz, BRDCTL_FWCMD_PARAM); 698 1.1 thorpej 699 1.66 andvar /* now clear this interrupt, possibly enabling another */ 700 1.1 thorpej CZ_PLX_WRITE(cz, PLX_LOCAL_PCI_DOORBELL, command); 701 1.1 thorpej 702 1.10 thorpej if (cz->cz_ports == NULL) { 703 1.10 thorpej #ifdef CZ_DEBUG 704 1.10 thorpej printf("%s: interrupt on channel %d, but no channels\n", 705 1.56 chs device_xname(cz->cz_dev), channel); 706 1.10 thorpej #endif 707 1.10 thorpej continue; 708 1.10 thorpej } 709 1.10 thorpej 710 1.1 thorpej sc = &cz->cz_ports[channel]; 711 1.1 thorpej 712 1.1 thorpej if (sc->sc_channel == CZTTY_CHANNEL_DEAD) 713 1.1 thorpej break; 714 1.1 thorpej 715 1.1 thorpej tp = sc->sc_tty; 716 1.1 thorpej 717 1.1 thorpej switch (command) { 718 1.1 thorpej case C_CM_TXFEMPTY: /* transmit cases */ 719 1.1 thorpej case C_CM_TXBEMPTY: 720 1.1 thorpej case C_CM_TXLOWWM: 721 1.1 thorpej case C_CM_INTBACK: 722 1.1 thorpej if (!ISSET(tp->t_state, TS_ISOPEN)) { 723 1.1 thorpej #ifdef CZ_DEBUG 724 1.1 thorpej printf("%s: tx intr on closed channel %d\n", 725 1.56 chs device_xname(cz->cz_dev), channel); 726 1.1 thorpej #endif 727 1.1 thorpej break; 728 1.1 thorpej } 729 1.1 thorpej 730 1.1 thorpej if (cztty_transmit(sc, tp)) { 731 1.1 thorpej /* 732 1.1 thorpej * Do wakeup stuff here. 733 1.1 thorpej */ 734 1.65 riastrad ttylock(tp); /* XXX */ 735 1.1 thorpej ttwakeup(tp); 736 1.65 riastrad ttyunlock(tp); /* XXX */ 737 1.1 thorpej wakeup(tp); 738 1.1 thorpej } 739 1.1 thorpej break; 740 1.1 thorpej 741 1.1 thorpej case C_CM_RXNNDT: /* receive cases */ 742 1.1 thorpej case C_CM_RXHIWM: 743 1.1 thorpej case C_CM_INTBACK2: /* from restart ?? */ 744 1.1 thorpej #if 0 745 1.1 thorpej case C_CM_ICHAR: 746 1.1 thorpej #endif 747 1.1 thorpej if (!ISSET(tp->t_state, TS_ISOPEN)) { 748 1.1 thorpej CZTTY_BUF_WRITE(sc, BUFCTL_RX_GET, 749 1.1 thorpej CZTTY_BUF_READ(sc, BUFCTL_RX_PUT)); 750 1.1 thorpej break; 751 1.1 thorpej } 752 1.1 thorpej 753 1.1 thorpej if (cztty_receive(sc, tp)) { 754 1.1 thorpej /* 755 1.1 thorpej * Do wakeup stuff here. 756 1.1 thorpej */ 757 1.65 riastrad ttylock(tp); /* XXX */ 758 1.1 thorpej ttwakeup(tp); 759 1.65 riastrad ttyunlock(tp); /* XXX */ 760 1.1 thorpej wakeup(tp); 761 1.1 thorpej } 762 1.1 thorpej break; 763 1.1 thorpej 764 1.1 thorpej case C_CM_MDCD: 765 1.1 thorpej if (!ISSET(tp->t_state, TS_ISOPEN)) 766 1.1 thorpej break; 767 1.1 thorpej 768 1.11 eeh (void) (*tp->t_linesw->l_modem)(tp, 769 1.1 thorpej ISSET(C_RS_DCD, CZTTY_CHAN_READ(sc, 770 1.1 thorpej CHNCTL_RS_STATUS))); 771 1.1 thorpej break; 772 1.1 thorpej 773 1.4 thorpej case C_CM_MDSR: 774 1.4 thorpej case C_CM_MRI: 775 1.5 thorpej case C_CM_MCTS: 776 1.5 thorpej case C_CM_MRTS: 777 1.4 thorpej break; 778 1.4 thorpej 779 1.6 thorpej case C_CM_IOCTLW: 780 1.6 thorpej break; 781 1.6 thorpej 782 1.1 thorpej case C_CM_PR_ERROR: 783 1.1 thorpej sc->sc_parity_errors++; 784 1.1 thorpej goto error_common; 785 1.1 thorpej 786 1.1 thorpej case C_CM_FR_ERROR: 787 1.1 thorpej sc->sc_framing_errors++; 788 1.1 thorpej goto error_common; 789 1.1 thorpej 790 1.1 thorpej case C_CM_OVR_ERROR: 791 1.1 thorpej sc->sc_overflows++; 792 1.1 thorpej error_common: 793 1.1 thorpej if (sc->sc_errors++ == 0) 794 1.1 thorpej callout_reset(&sc->sc_diag_ch, 60 * hz, 795 1.1 thorpej cztty_diag, sc); 796 1.1 thorpej break; 797 1.1 thorpej 798 1.4 thorpej case C_CM_RXBRK: 799 1.6 thorpej if (!ISSET(tp->t_state, TS_ISOPEN)) 800 1.6 thorpej break; 801 1.6 thorpej 802 1.6 thorpej /* 803 1.6 thorpej * A break is a \000 character with TTY_FE error 804 1.6 thorpej * flags set. So TTY_FE by itself works. 805 1.6 thorpej */ 806 1.11 eeh (*tp->t_linesw->l_rint)(TTY_FE, tp); 807 1.65 riastrad ttylock(tp); /* XXX */ 808 1.6 thorpej ttwakeup(tp); 809 1.65 riastrad ttyunlock(tp); /* XXX */ 810 1.6 thorpej wakeup(tp); 811 1.4 thorpej break; 812 1.4 thorpej 813 1.1 thorpej default: 814 1.1 thorpej #ifdef CZ_DEBUG 815 1.1 thorpej printf("%s: channel %d: Unknown interrupt 0x%x\n", 816 1.56 chs device_xname(cz->cz_dev), sc->sc_channel, command); 817 1.1 thorpej #endif 818 1.1 thorpej break; 819 1.1 thorpej } 820 1.1 thorpej } 821 1.1 thorpej 822 1.1 thorpej return (rval); 823 1.1 thorpej } 824 1.1 thorpej 825 1.1 thorpej /* 826 1.1 thorpej * cz_wait_pci_doorbell: 827 1.1 thorpej * 828 1.1 thorpej * Wait for the pci doorbell to be clear - wait for pending 829 1.1 thorpej * activity to drain. 830 1.1 thorpej */ 831 1.32 thorpej static int 832 1.1 thorpej cz_wait_pci_doorbell(struct cz_softc *cz, const char *wstring) 833 1.1 thorpej { 834 1.1 thorpej int error; 835 1.1 thorpej 836 1.1 thorpej while (CZ_PLX_READ(cz, PLX_PCI_LOCAL_DOORBELL)) { 837 1.63 riastrad error = tsleep(cz, TTIPRI | PCATCH, wstring, uimax(1, hz/100)); 838 1.1 thorpej if ((error != 0) && (error != EWOULDBLOCK)) 839 1.1 thorpej return (error); 840 1.1 thorpej } 841 1.1 thorpej return (0); 842 1.1 thorpej } 843 1.1 thorpej 844 1.1 thorpej /***************************************************************************** 845 1.1 thorpej * Cyclades-Z TTY code starts here... 846 1.1 thorpej *****************************************************************************/ 847 1.1 thorpej 848 1.61 christos #define CZTTY_DIALOUT(dev) TTDIALOUT(dev) 849 1.61 christos #define CZTTY_UNIT(dev) TTUNIT(dev) 850 1.1 thorpej #define CZTTY_CZ(sc) ((sc)->sc_parent) 851 1.1 thorpej 852 1.14 thorpej #define CZTTY_SOFTC(dev) cztty_getttysoftc(dev) 853 1.7 wrstuden 854 1.32 thorpej static struct cztty_softc * 855 1.7 wrstuden cztty_getttysoftc(dev_t dev) 856 1.7 wrstuden { 857 1.61 christos int i, j, k = 0, u = CZTTY_UNIT(dev); 858 1.29 chs struct cz_softc *cz = NULL; 859 1.7 wrstuden 860 1.7 wrstuden for (i = 0, j = 0; i < cz_cd.cd_ndevs; i++) { 861 1.7 wrstuden k = j; 862 1.49 tsutsui cz = device_lookup_private(&cz_cd, i); 863 1.13 thorpej if (cz == NULL) 864 1.13 thorpej continue; 865 1.10 thorpej if (cz->cz_ports == NULL) 866 1.10 thorpej continue; 867 1.7 wrstuden j += cz->cz_nchannels; 868 1.7 wrstuden if (j > u) 869 1.7 wrstuden break; 870 1.7 wrstuden } 871 1.7 wrstuden 872 1.15 thorpej if (i >= cz_cd.cd_ndevs) 873 1.7 wrstuden return (NULL); 874 1.15 thorpej else 875 1.7 wrstuden return (&cz->cz_ports[u - k]); 876 1.1 thorpej } 877 1.1 thorpej 878 1.1 thorpej /* 879 1.1 thorpej * czttytty: 880 1.1 thorpej * 881 1.1 thorpej * Return a pointer to our tty. 882 1.1 thorpej */ 883 1.32 thorpej static struct tty * 884 1.1 thorpej czttytty(dev_t dev) 885 1.1 thorpej { 886 1.1 thorpej struct cztty_softc *sc = CZTTY_SOFTC(dev); 887 1.1 thorpej 888 1.1 thorpej #ifdef DIAGNOSTIC 889 1.1 thorpej if (sc == NULL) 890 1.1 thorpej panic("czttytty"); 891 1.1 thorpej #endif 892 1.1 thorpej 893 1.1 thorpej return (sc->sc_tty); 894 1.1 thorpej } 895 1.1 thorpej 896 1.1 thorpej /* 897 1.1 thorpej * cztty_shutdown: 898 1.1 thorpej * 899 1.1 thorpej * Shut down a port. 900 1.1 thorpej */ 901 1.32 thorpej static void 902 1.1 thorpej cztty_shutdown(struct cztty_softc *sc) 903 1.1 thorpej { 904 1.1 thorpej struct cz_softc *cz = CZTTY_CZ(sc); 905 1.1 thorpej struct tty *tp = sc->sc_tty; 906 1.1 thorpej int s; 907 1.1 thorpej 908 1.1 thorpej s = spltty(); 909 1.1 thorpej 910 1.1 thorpej /* Clear any break condition set with TIOCSBRK. */ 911 1.1 thorpej cztty_break(sc, 0); 912 1.1 thorpej 913 1.1 thorpej /* 914 1.1 thorpej * Hang up if necessary. Wait a bit, so the other side has time to 915 1.1 thorpej * notice even if we immediately open the port again. 916 1.1 thorpej */ 917 1.1 thorpej if (ISSET(tp->t_cflag, HUPCL)) { 918 1.1 thorpej cztty_modem(sc, 0); 919 1.1 thorpej (void) tsleep(tp, TTIPRI, ttclos, hz); 920 1.1 thorpej } 921 1.1 thorpej 922 1.1 thorpej /* Disable the channel. */ 923 1.1 thorpej cz_wait_pci_doorbell(cz, "czdis"); 924 1.1 thorpej CZTTY_CHAN_WRITE(sc, CHNCTL_OP_MODE, C_CH_DISABLE); 925 1.1 thorpej CZ_FWCTL_WRITE(cz, BRDCTL_HCMD_CHANNEL, sc->sc_channel); 926 1.1 thorpej CZ_PLX_WRITE(cz, PLX_PCI_LOCAL_DOORBELL, C_CM_IOCTL); 927 1.1 thorpej 928 1.1 thorpej if ((--cz->cz_nopenchan == 0) && (cz->cz_ih == NULL)) { 929 1.1 thorpej #ifdef CZ_DEBUG 930 1.56 chs printf("%s: Disabling polling\n", device_xname(cz->cz_dev)); 931 1.1 thorpej #endif 932 1.1 thorpej callout_stop(&cz->cz_callout); 933 1.1 thorpej } 934 1.1 thorpej 935 1.1 thorpej splx(s); 936 1.1 thorpej } 937 1.1 thorpej 938 1.1 thorpej /* 939 1.1 thorpej * czttyopen: 940 1.1 thorpej * 941 1.1 thorpej * Open a Cyclades-Z serial port. 942 1.1 thorpej */ 943 1.32 thorpej static int 944 1.42 christos czttyopen(dev_t dev, int flags, int mode, struct lwp *l) 945 1.1 thorpej { 946 1.1 thorpej struct cztty_softc *sc = CZTTY_SOFTC(dev); 947 1.1 thorpej struct cz_softc *cz; 948 1.1 thorpej struct tty *tp; 949 1.1 thorpej int s, error; 950 1.1 thorpej 951 1.1 thorpej if (sc == NULL) 952 1.1 thorpej return (ENXIO); 953 1.1 thorpej 954 1.1 thorpej if (sc->sc_channel == CZTTY_CHANNEL_DEAD) 955 1.1 thorpej return (ENXIO); 956 1.1 thorpej 957 1.1 thorpej cz = CZTTY_CZ(sc); 958 1.1 thorpej tp = sc->sc_tty; 959 1.1 thorpej 960 1.39 elad if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) 961 1.1 thorpej return (EBUSY); 962 1.1 thorpej 963 1.1 thorpej s = spltty(); 964 1.1 thorpej 965 1.1 thorpej /* 966 1.1 thorpej * Do the following iff this is a first open. 967 1.1 thorpej */ 968 1.1 thorpej if (!ISSET(tp->t_state, TS_ISOPEN) && (tp->t_wopen == 0)) { 969 1.1 thorpej struct termios t; 970 1.1 thorpej 971 1.1 thorpej tp->t_dev = dev; 972 1.1 thorpej 973 1.1 thorpej /* If we're turning things on, enable interrupts */ 974 1.1 thorpej if ((cz->cz_nopenchan++ == 0) && (cz->cz_ih == NULL)) { 975 1.1 thorpej #ifdef CZ_DEBUG 976 1.1 thorpej printf("%s: Enabling polling.\n", 977 1.56 chs device_xname(cz->cz_dev)); 978 1.1 thorpej #endif 979 1.1 thorpej callout_reset(&cz->cz_callout, cz_timeout_ticks, 980 1.1 thorpej cz_poll, cz); 981 1.1 thorpej } 982 1.1 thorpej 983 1.1 thorpej /* 984 1.1 thorpej * Enable the channel. Don't actually ring the 985 1.1 thorpej * doorbell here; czttyparam() will do it for us. 986 1.1 thorpej */ 987 1.1 thorpej cz_wait_pci_doorbell(cz, "czopen"); 988 1.1 thorpej 989 1.1 thorpej CZTTY_CHAN_WRITE(sc, CHNCTL_OP_MODE, C_CH_ENABLE); 990 1.1 thorpej 991 1.1 thorpej /* 992 1.1 thorpej * Initialize the termios status to the defaults. Add in the 993 1.1 thorpej * sticky bits from TIOCSFLAGS. 994 1.1 thorpej */ 995 1.1 thorpej t.c_ispeed = 0; 996 1.1 thorpej t.c_ospeed = TTYDEF_SPEED; 997 1.1 thorpej t.c_cflag = TTYDEF_CFLAG; 998 1.1 thorpej if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL)) 999 1.1 thorpej SET(t.c_cflag, CLOCAL); 1000 1.1 thorpej if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS)) 1001 1.1 thorpej SET(t.c_cflag, CRTSCTS); 1002 1.1 thorpej 1003 1.1 thorpej /* 1004 1.1 thorpej * Reset the input and output rings. Do this before 1005 1.1 thorpej * we call czttyparam(), as that function enables 1006 1.1 thorpej * the channel. 1007 1.1 thorpej */ 1008 1.1 thorpej CZTTY_BUF_WRITE(sc, BUFCTL_RX_GET, 1009 1.1 thorpej CZTTY_BUF_READ(sc, BUFCTL_RX_PUT)); 1010 1.1 thorpej CZTTY_BUF_WRITE(sc, BUFCTL_TX_PUT, 1011 1.1 thorpej CZTTY_BUF_READ(sc, BUFCTL_TX_GET)); 1012 1.1 thorpej 1013 1.1 thorpej /* Make sure czttyparam() will see changes. */ 1014 1.1 thorpej tp->t_ospeed = 0; 1015 1.1 thorpej (void) czttyparam(tp, &t); 1016 1.1 thorpej tp->t_iflag = TTYDEF_IFLAG; 1017 1.1 thorpej tp->t_oflag = TTYDEF_OFLAG; 1018 1.1 thorpej tp->t_lflag = TTYDEF_LFLAG; 1019 1.1 thorpej ttychars(tp); 1020 1.1 thorpej ttsetwater(tp); 1021 1.1 thorpej 1022 1.1 thorpej /* 1023 1.1 thorpej * Turn on DTR. We must always do this, even if carrier is not 1024 1.1 thorpej * present, because otherwise we'd have to use TIOCSDTR 1025 1.1 thorpej * immediately after setting CLOCAL, which applications do not 1026 1.1 thorpej * expect. We always assert DTR while the device is open 1027 1.1 thorpej * unless explicitly requested to deassert it. 1028 1.1 thorpej */ 1029 1.1 thorpej cztty_modem(sc, 1); 1030 1.1 thorpej } 1031 1.1 thorpej 1032 1.1 thorpej splx(s); 1033 1.1 thorpej 1034 1.1 thorpej error = ttyopen(tp, CZTTY_DIALOUT(dev), ISSET(flags, O_NONBLOCK)); 1035 1.1 thorpej if (error) 1036 1.1 thorpej goto bad; 1037 1.1 thorpej 1038 1.11 eeh error = (*tp->t_linesw->l_open)(dev, tp); 1039 1.1 thorpej if (error) 1040 1.1 thorpej goto bad; 1041 1.1 thorpej 1042 1.1 thorpej return (0); 1043 1.1 thorpej 1044 1.1 thorpej bad: 1045 1.2 thorpej if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 1046 1.1 thorpej /* 1047 1.1 thorpej * We failed to open the device, and nobody else had it opened. 1048 1.1 thorpej * Clean up the state as appropriate. 1049 1.1 thorpej */ 1050 1.1 thorpej cztty_shutdown(sc); 1051 1.1 thorpej } 1052 1.1 thorpej 1053 1.1 thorpej return (error); 1054 1.1 thorpej } 1055 1.1 thorpej 1056 1.1 thorpej /* 1057 1.1 thorpej * czttyclose: 1058 1.1 thorpej * 1059 1.1 thorpej * Close a Cyclades-Z serial port. 1060 1.1 thorpej */ 1061 1.32 thorpej static int 1062 1.42 christos czttyclose(dev_t dev, int flags, int mode, struct lwp *l) 1063 1.1 thorpej { 1064 1.1 thorpej struct cztty_softc *sc = CZTTY_SOFTC(dev); 1065 1.1 thorpej struct tty *tp = sc->sc_tty; 1066 1.1 thorpej 1067 1.1 thorpej /* XXX This is for cons.c. */ 1068 1.2 thorpej if (!ISSET(tp->t_state, TS_ISOPEN)) 1069 1.1 thorpej return (0); 1070 1.1 thorpej 1071 1.11 eeh (*tp->t_linesw->l_close)(tp, flags); 1072 1.1 thorpej ttyclose(tp); 1073 1.1 thorpej 1074 1.2 thorpej if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 1075 1.1 thorpej /* 1076 1.1 thorpej * Although we got a last close, the device may still be in 1077 1.1 thorpej * use; e.g. if this was the dialout node, and there are still 1078 1.1 thorpej * processes waiting for carrier on the non-dialout node. 1079 1.1 thorpej */ 1080 1.1 thorpej cztty_shutdown(sc); 1081 1.1 thorpej } 1082 1.1 thorpej 1083 1.1 thorpej return (0); 1084 1.1 thorpej } 1085 1.1 thorpej 1086 1.1 thorpej /* 1087 1.1 thorpej * czttyread: 1088 1.1 thorpej * 1089 1.1 thorpej * Read from a Cyclades-Z serial port. 1090 1.1 thorpej */ 1091 1.32 thorpej static int 1092 1.1 thorpej czttyread(dev_t dev, struct uio *uio, int flags) 1093 1.1 thorpej { 1094 1.1 thorpej struct cztty_softc *sc = CZTTY_SOFTC(dev); 1095 1.1 thorpej struct tty *tp = sc->sc_tty; 1096 1.1 thorpej 1097 1.11 eeh return ((*tp->t_linesw->l_read)(tp, uio, flags)); 1098 1.1 thorpej } 1099 1.1 thorpej 1100 1.1 thorpej /* 1101 1.1 thorpej * czttywrite: 1102 1.1 thorpej * 1103 1.1 thorpej * Write to a Cyclades-Z serial port. 1104 1.1 thorpej */ 1105 1.32 thorpej static int 1106 1.1 thorpej czttywrite(dev_t dev, struct uio *uio, int flags) 1107 1.1 thorpej { 1108 1.1 thorpej struct cztty_softc *sc = CZTTY_SOFTC(dev); 1109 1.1 thorpej struct tty *tp = sc->sc_tty; 1110 1.1 thorpej 1111 1.11 eeh return ((*tp->t_linesw->l_write)(tp, uio, flags)); 1112 1.16 scw } 1113 1.16 scw 1114 1.16 scw /* 1115 1.16 scw * czttypoll: 1116 1.16 scw * 1117 1.16 scw * Poll a Cyclades-Z serial port. 1118 1.16 scw */ 1119 1.32 thorpej static int 1120 1.34 christos czttypoll(dev_t dev, int events, struct lwp *l) 1121 1.16 scw { 1122 1.16 scw struct cztty_softc *sc = CZTTY_SOFTC(dev); 1123 1.16 scw struct tty *tp = sc->sc_tty; 1124 1.30 perry 1125 1.34 christos return ((*tp->t_linesw->l_poll)(tp, events, l)); 1126 1.1 thorpej } 1127 1.1 thorpej 1128 1.1 thorpej /* 1129 1.1 thorpej * czttyioctl: 1130 1.1 thorpej * 1131 1.1 thorpej * Perform a control operation on a Cyclades-Z serial port. 1132 1.1 thorpej */ 1133 1.32 thorpej static int 1134 1.43 christos czttyioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 1135 1.1 thorpej { 1136 1.1 thorpej struct cztty_softc *sc = CZTTY_SOFTC(dev); 1137 1.1 thorpej struct tty *tp = sc->sc_tty; 1138 1.1 thorpej int s, error; 1139 1.1 thorpej 1140 1.34 christos error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l); 1141 1.19 atatat if (error != EPASSTHROUGH) 1142 1.1 thorpej return (error); 1143 1.1 thorpej 1144 1.34 christos error = ttioctl(tp, cmd, data, flag, l); 1145 1.19 atatat if (error != EPASSTHROUGH) 1146 1.1 thorpej return (error); 1147 1.1 thorpej 1148 1.1 thorpej error = 0; 1149 1.1 thorpej 1150 1.1 thorpej s = spltty(); 1151 1.1 thorpej 1152 1.1 thorpej switch (cmd) { 1153 1.1 thorpej case TIOCSBRK: 1154 1.1 thorpej cztty_break(sc, 1); 1155 1.1 thorpej break; 1156 1.1 thorpej 1157 1.1 thorpej case TIOCCBRK: 1158 1.1 thorpej cztty_break(sc, 0); 1159 1.1 thorpej break; 1160 1.1 thorpej 1161 1.1 thorpej case TIOCGFLAGS: 1162 1.1 thorpej *(int *)data = sc->sc_swflags; 1163 1.1 thorpej break; 1164 1.1 thorpej 1165 1.1 thorpej case TIOCSFLAGS: 1166 1.40 elad error = kauth_authorize_device_tty(l->l_cred, 1167 1.40 elad KAUTH_DEVICE_TTY_PRIVSET, tp); 1168 1.1 thorpej if (error) 1169 1.1 thorpej break; 1170 1.1 thorpej sc->sc_swflags = *(int *)data; 1171 1.1 thorpej break; 1172 1.1 thorpej 1173 1.1 thorpej case TIOCSDTR: 1174 1.1 thorpej cztty_modem(sc, 1); 1175 1.1 thorpej break; 1176 1.1 thorpej 1177 1.1 thorpej case TIOCCDTR: 1178 1.1 thorpej cztty_modem(sc, 0); 1179 1.1 thorpej break; 1180 1.1 thorpej 1181 1.1 thorpej case TIOCMSET: 1182 1.1 thorpej case TIOCMBIS: 1183 1.1 thorpej case TIOCMBIC: 1184 1.1 thorpej tiocm_to_cztty(sc, cmd, *(int *)data); 1185 1.1 thorpej break; 1186 1.1 thorpej 1187 1.1 thorpej case TIOCMGET: 1188 1.1 thorpej *(int *)data = cztty_to_tiocm(sc); 1189 1.1 thorpej break; 1190 1.1 thorpej 1191 1.1 thorpej default: 1192 1.19 atatat error = EPASSTHROUGH; 1193 1.1 thorpej break; 1194 1.1 thorpej } 1195 1.1 thorpej 1196 1.1 thorpej splx(s); 1197 1.1 thorpej 1198 1.1 thorpej return (error); 1199 1.1 thorpej } 1200 1.1 thorpej 1201 1.1 thorpej /* 1202 1.1 thorpej * cztty_break: 1203 1.1 thorpej * 1204 1.1 thorpej * Set or clear BREAK on a port. 1205 1.1 thorpej */ 1206 1.32 thorpej static void 1207 1.1 thorpej cztty_break(struct cztty_softc *sc, int onoff) 1208 1.1 thorpej { 1209 1.1 thorpej struct cz_softc *cz = CZTTY_CZ(sc); 1210 1.1 thorpej 1211 1.1 thorpej cz_wait_pci_doorbell(cz, "czbreak"); 1212 1.1 thorpej 1213 1.1 thorpej CZ_FWCTL_WRITE(cz, BRDCTL_HCMD_CHANNEL, sc->sc_channel); 1214 1.1 thorpej CZ_PLX_WRITE(cz, PLX_PCI_LOCAL_DOORBELL, 1215 1.1 thorpej onoff ? C_CM_SET_BREAK : C_CM_CLR_BREAK); 1216 1.1 thorpej } 1217 1.1 thorpej 1218 1.1 thorpej /* 1219 1.1 thorpej * cztty_modem: 1220 1.1 thorpej * 1221 1.1 thorpej * Set or clear DTR on a port. 1222 1.1 thorpej */ 1223 1.32 thorpej static void 1224 1.1 thorpej cztty_modem(struct cztty_softc *sc, int onoff) 1225 1.1 thorpej { 1226 1.1 thorpej struct cz_softc *cz = CZTTY_CZ(sc); 1227 1.1 thorpej 1228 1.1 thorpej if (sc->sc_rs_control_dtr == 0) 1229 1.1 thorpej return; 1230 1.1 thorpej 1231 1.1 thorpej cz_wait_pci_doorbell(cz, "czmod"); 1232 1.1 thorpej 1233 1.1 thorpej if (onoff) 1234 1.1 thorpej sc->sc_chanctl_rs_control |= sc->sc_rs_control_dtr; 1235 1.1 thorpej else 1236 1.1 thorpej sc->sc_chanctl_rs_control &= ~sc->sc_rs_control_dtr; 1237 1.1 thorpej CZTTY_CHAN_WRITE(sc, CHNCTL_RS_CONTROL, sc->sc_chanctl_rs_control); 1238 1.1 thorpej 1239 1.1 thorpej CZ_FWCTL_WRITE(cz, BRDCTL_HCMD_CHANNEL, sc->sc_channel); 1240 1.1 thorpej CZ_PLX_WRITE(cz, PLX_PCI_LOCAL_DOORBELL, C_CM_IOCTLM); 1241 1.1 thorpej } 1242 1.1 thorpej 1243 1.1 thorpej /* 1244 1.1 thorpej * tiocm_to_cztty: 1245 1.1 thorpej * 1246 1.1 thorpej * Process TIOCM* ioctls. 1247 1.1 thorpej */ 1248 1.32 thorpej static void 1249 1.1 thorpej tiocm_to_cztty(struct cztty_softc *sc, u_long how, int ttybits) 1250 1.1 thorpej { 1251 1.1 thorpej struct cz_softc *cz = CZTTY_CZ(sc); 1252 1.1 thorpej u_int32_t czttybits; 1253 1.1 thorpej 1254 1.1 thorpej czttybits = 0; 1255 1.1 thorpej if (ISSET(ttybits, TIOCM_DTR)) 1256 1.1 thorpej SET(czttybits, C_RS_DTR); 1257 1.1 thorpej if (ISSET(ttybits, TIOCM_RTS)) 1258 1.1 thorpej SET(czttybits, C_RS_RTS); 1259 1.1 thorpej 1260 1.1 thorpej cz_wait_pci_doorbell(cz, "cztiocm"); 1261 1.1 thorpej 1262 1.1 thorpej switch (how) { 1263 1.1 thorpej case TIOCMBIC: 1264 1.1 thorpej CLR(sc->sc_chanctl_rs_control, czttybits); 1265 1.1 thorpej break; 1266 1.1 thorpej 1267 1.1 thorpej case TIOCMBIS: 1268 1.3 thorpej SET(sc->sc_chanctl_rs_control, czttybits); 1269 1.1 thorpej break; 1270 1.1 thorpej 1271 1.1 thorpej case TIOCMSET: 1272 1.1 thorpej CLR(sc->sc_chanctl_rs_control, C_RS_DTR | C_RS_RTS); 1273 1.1 thorpej SET(sc->sc_chanctl_rs_control, czttybits); 1274 1.1 thorpej break; 1275 1.1 thorpej } 1276 1.1 thorpej 1277 1.1 thorpej CZTTY_CHAN_WRITE(sc, CHNCTL_RS_CONTROL, sc->sc_chanctl_rs_control); 1278 1.1 thorpej 1279 1.1 thorpej CZ_FWCTL_WRITE(cz, BRDCTL_HCMD_CHANNEL, sc->sc_channel); 1280 1.1 thorpej CZ_PLX_WRITE(cz, PLX_PCI_LOCAL_DOORBELL, C_CM_IOCTLM); 1281 1.1 thorpej } 1282 1.1 thorpej 1283 1.1 thorpej /* 1284 1.1 thorpej * cztty_to_tiocm: 1285 1.1 thorpej * 1286 1.1 thorpej * Process the TIOCMGET ioctl. 1287 1.1 thorpej */ 1288 1.32 thorpej static int 1289 1.1 thorpej cztty_to_tiocm(struct cztty_softc *sc) 1290 1.1 thorpej { 1291 1.1 thorpej struct cz_softc *cz = CZTTY_CZ(sc); 1292 1.1 thorpej u_int32_t rs_status, op_mode; 1293 1.1 thorpej int ttybits = 0; 1294 1.1 thorpej 1295 1.1 thorpej cz_wait_pci_doorbell(cz, "cztty"); 1296 1.1 thorpej 1297 1.1 thorpej rs_status = CZTTY_CHAN_READ(sc, CHNCTL_RS_STATUS); 1298 1.1 thorpej op_mode = CZTTY_CHAN_READ(sc, CHNCTL_OP_MODE); 1299 1.1 thorpej 1300 1.1 thorpej if (ISSET(rs_status, C_RS_RTS)) 1301 1.1 thorpej SET(ttybits, TIOCM_RTS); 1302 1.1 thorpej if (ISSET(rs_status, C_RS_CTS)) 1303 1.1 thorpej SET(ttybits, TIOCM_CTS); 1304 1.1 thorpej if (ISSET(rs_status, C_RS_DCD)) 1305 1.1 thorpej SET(ttybits, TIOCM_CAR); 1306 1.1 thorpej if (ISSET(rs_status, C_RS_DTR)) 1307 1.1 thorpej SET(ttybits, TIOCM_DTR); 1308 1.1 thorpej if (ISSET(rs_status, C_RS_RI)) 1309 1.1 thorpej SET(ttybits, TIOCM_RNG); 1310 1.1 thorpej if (ISSET(rs_status, C_RS_DSR)) 1311 1.1 thorpej SET(ttybits, TIOCM_DSR); 1312 1.1 thorpej 1313 1.1 thorpej if (ISSET(op_mode, C_CH_ENABLE)) 1314 1.1 thorpej SET(ttybits, TIOCM_LE); 1315 1.1 thorpej 1316 1.1 thorpej return (ttybits); 1317 1.1 thorpej } 1318 1.1 thorpej 1319 1.1 thorpej /* 1320 1.1 thorpej * czttyparam: 1321 1.1 thorpej * 1322 1.1 thorpej * Set Cyclades-Z serial port parameters from termios. 1323 1.1 thorpej * 1324 1.1 thorpej * XXX Should just copy the whole termios after making 1325 1.1 thorpej * XXX sure all the changes could be done. 1326 1.1 thorpej */ 1327 1.32 thorpej static int 1328 1.1 thorpej czttyparam(struct tty *tp, struct termios *t) 1329 1.1 thorpej { 1330 1.1 thorpej struct cztty_softc *sc = CZTTY_SOFTC(tp->t_dev); 1331 1.1 thorpej struct cz_softc *cz = CZTTY_CZ(sc); 1332 1.1 thorpej u_int32_t rs_status; 1333 1.1 thorpej int ospeed, cflag; 1334 1.1 thorpej 1335 1.1 thorpej ospeed = t->c_ospeed; 1336 1.1 thorpej cflag = t->c_cflag; 1337 1.1 thorpej 1338 1.1 thorpej /* Check requested parameters. */ 1339 1.1 thorpej if (ospeed < 0) 1340 1.1 thorpej return (EINVAL); 1341 1.1 thorpej if (t->c_ispeed && t->c_ispeed != ospeed) 1342 1.1 thorpej return (EINVAL); 1343 1.1 thorpej 1344 1.1 thorpej if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR)) { 1345 1.1 thorpej SET(cflag, CLOCAL); 1346 1.1 thorpej CLR(cflag, HUPCL); 1347 1.1 thorpej } 1348 1.1 thorpej 1349 1.1 thorpej /* 1350 1.1 thorpej * If there were no changes, don't do anything. This avoids dropping 1351 1.1 thorpej * input and improves performance when all we did was frob things like 1352 1.1 thorpej * VMIN and VTIME. 1353 1.1 thorpej */ 1354 1.1 thorpej if (tp->t_ospeed == ospeed && 1355 1.1 thorpej tp->t_cflag == cflag) 1356 1.1 thorpej return (0); 1357 1.1 thorpej 1358 1.1 thorpej /* Data bits. */ 1359 1.1 thorpej sc->sc_chanctl_comm_data_l = 0; 1360 1.1 thorpej switch (t->c_cflag & CSIZE) { 1361 1.1 thorpej case CS5: 1362 1.1 thorpej sc->sc_chanctl_comm_data_l |= C_DL_CS5; 1363 1.1 thorpej break; 1364 1.1 thorpej 1365 1.1 thorpej case CS6: 1366 1.1 thorpej sc->sc_chanctl_comm_data_l |= C_DL_CS6; 1367 1.1 thorpej break; 1368 1.1 thorpej 1369 1.1 thorpej case CS7: 1370 1.1 thorpej sc->sc_chanctl_comm_data_l |= C_DL_CS7; 1371 1.1 thorpej break; 1372 1.1 thorpej 1373 1.1 thorpej case CS8: 1374 1.1 thorpej sc->sc_chanctl_comm_data_l |= C_DL_CS8; 1375 1.1 thorpej break; 1376 1.1 thorpej } 1377 1.1 thorpej 1378 1.1 thorpej /* Stop bits. */ 1379 1.1 thorpej if (t->c_cflag & CSTOPB) { 1380 1.1 thorpej if ((sc->sc_chanctl_comm_data_l & C_DL_CS) == C_DL_CS5) 1381 1.1 thorpej sc->sc_chanctl_comm_data_l |= C_DL_15STOP; 1382 1.1 thorpej else 1383 1.1 thorpej sc->sc_chanctl_comm_data_l |= C_DL_2STOP; 1384 1.1 thorpej } else 1385 1.1 thorpej sc->sc_chanctl_comm_data_l |= C_DL_1STOP; 1386 1.1 thorpej 1387 1.1 thorpej /* Parity. */ 1388 1.1 thorpej if (t->c_cflag & PARENB) { 1389 1.1 thorpej if (t->c_cflag & PARODD) 1390 1.1 thorpej sc->sc_chanctl_comm_parity = C_PR_ODD; 1391 1.1 thorpej else 1392 1.1 thorpej sc->sc_chanctl_comm_parity = C_PR_EVEN; 1393 1.1 thorpej } else 1394 1.1 thorpej sc->sc_chanctl_comm_parity = C_PR_NONE; 1395 1.1 thorpej 1396 1.1 thorpej /* 1397 1.1 thorpej * Initialize flow control pins depending on the current flow control 1398 1.1 thorpej * mode. 1399 1.1 thorpej */ 1400 1.1 thorpej if (ISSET(t->c_cflag, CRTSCTS)) { 1401 1.1 thorpej sc->sc_rs_control_dtr = C_RS_DTR; 1402 1.1 thorpej sc->sc_chanctl_hw_flow = C_RS_CTS | C_RS_RTS; 1403 1.1 thorpej } else if (ISSET(t->c_cflag, MDMBUF)) { 1404 1.4 thorpej sc->sc_rs_control_dtr = 0; 1405 1.1 thorpej sc->sc_chanctl_hw_flow = C_RS_DCD | C_RS_DTR; 1406 1.1 thorpej } else { 1407 1.1 thorpej /* 1408 1.1 thorpej * If no flow control, then always set RTS. This will make 1409 1.1 thorpej * the other side happy if it mistakenly thinks we're doing 1410 1.1 thorpej * RTS/CTS flow control. 1411 1.1 thorpej */ 1412 1.1 thorpej sc->sc_rs_control_dtr = C_RS_DTR | C_RS_RTS; 1413 1.1 thorpej sc->sc_chanctl_hw_flow = 0; 1414 1.1 thorpej if (ISSET(sc->sc_chanctl_rs_control, C_RS_DTR)) 1415 1.1 thorpej SET(sc->sc_chanctl_rs_control, C_RS_RTS); 1416 1.1 thorpej else 1417 1.1 thorpej CLR(sc->sc_chanctl_rs_control, C_RS_RTS); 1418 1.1 thorpej } 1419 1.1 thorpej 1420 1.1 thorpej /* Baud rate. */ 1421 1.1 thorpej sc->sc_chanctl_comm_baud = ospeed; 1422 1.1 thorpej 1423 1.1 thorpej /* Copy to tty. */ 1424 1.1 thorpej tp->t_ispeed = 0; 1425 1.1 thorpej tp->t_ospeed = t->c_ospeed; 1426 1.1 thorpej tp->t_cflag = t->c_cflag; 1427 1.1 thorpej 1428 1.1 thorpej /* 1429 1.1 thorpej * Now load the channel control structure. 1430 1.1 thorpej */ 1431 1.1 thorpej 1432 1.1 thorpej cz_wait_pci_doorbell(cz, "czparam"); 1433 1.1 thorpej 1434 1.1 thorpej CZTTY_CHAN_WRITE(sc, CHNCTL_COMM_BAUD, sc->sc_chanctl_comm_baud); 1435 1.1 thorpej CZTTY_CHAN_WRITE(sc, CHNCTL_COMM_DATA_L, sc->sc_chanctl_comm_data_l); 1436 1.1 thorpej CZTTY_CHAN_WRITE(sc, CHNCTL_COMM_PARITY, sc->sc_chanctl_comm_parity); 1437 1.1 thorpej CZTTY_CHAN_WRITE(sc, CHNCTL_HW_FLOW, sc->sc_chanctl_hw_flow); 1438 1.1 thorpej CZTTY_CHAN_WRITE(sc, CHNCTL_RS_CONTROL, sc->sc_chanctl_rs_control); 1439 1.4 thorpej 1440 1.1 thorpej CZ_FWCTL_WRITE(cz, BRDCTL_HCMD_CHANNEL, sc->sc_channel); 1441 1.6 thorpej CZ_PLX_WRITE(cz, PLX_PCI_LOCAL_DOORBELL, C_CM_IOCTLW); 1442 1.1 thorpej 1443 1.1 thorpej cz_wait_pci_doorbell(cz, "czparam"); 1444 1.1 thorpej 1445 1.1 thorpej CZ_FWCTL_WRITE(cz, BRDCTL_HCMD_CHANNEL, sc->sc_channel); 1446 1.1 thorpej CZ_PLX_WRITE(cz, PLX_PCI_LOCAL_DOORBELL, C_CM_IOCTLM); 1447 1.1 thorpej 1448 1.1 thorpej cz_wait_pci_doorbell(cz, "czparam"); 1449 1.1 thorpej 1450 1.1 thorpej /* 1451 1.1 thorpej * Update the tty layer's idea of the carrier bit, in case we changed 1452 1.1 thorpej * CLOCAL. We don't hang up here; we only do that by explicit 1453 1.1 thorpej * request. 1454 1.1 thorpej */ 1455 1.1 thorpej rs_status = CZTTY_CHAN_READ(sc, CHNCTL_RS_STATUS); 1456 1.11 eeh (void) (*tp->t_linesw->l_modem)(tp, ISSET(rs_status, C_RS_DCD)); 1457 1.1 thorpej 1458 1.1 thorpej return (0); 1459 1.1 thorpej } 1460 1.1 thorpej 1461 1.1 thorpej /* 1462 1.1 thorpej * czttystart: 1463 1.1 thorpej * 1464 1.1 thorpej * Start or restart transmission. 1465 1.1 thorpej */ 1466 1.32 thorpej static void 1467 1.1 thorpej czttystart(struct tty *tp) 1468 1.1 thorpej { 1469 1.1 thorpej struct cztty_softc *sc = CZTTY_SOFTC(tp->t_dev); 1470 1.1 thorpej int s; 1471 1.1 thorpej 1472 1.1 thorpej s = spltty(); 1473 1.1 thorpej if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) 1474 1.1 thorpej goto out; 1475 1.47 ad if (!ttypull(tp)) 1476 1.47 ad goto out; 1477 1.1 thorpej cztty_transmit(sc, tp); 1478 1.1 thorpej out: 1479 1.1 thorpej splx(s); 1480 1.1 thorpej } 1481 1.1 thorpej 1482 1.1 thorpej /* 1483 1.1 thorpej * czttystop: 1484 1.1 thorpej * 1485 1.1 thorpej * Stop output, e.g., for ^S or output flush. 1486 1.1 thorpej */ 1487 1.32 thorpej static void 1488 1.42 christos czttystop(struct tty *tp, int flag) 1489 1.1 thorpej { 1490 1.1 thorpej 1491 1.1 thorpej /* 1492 1.1 thorpej * XXX We don't do anything here, yet. Mostly, I don't know 1493 1.1 thorpej * XXX exactly how this should be implemented on this device. 1494 1.1 thorpej * XXX We've given a big chunk of data to the MIPS already, 1495 1.1 thorpej * XXX and I don't know how we request the MIPS to stop sending 1496 1.1 thorpej * XXX the data. So, punt for now. --thorpej 1497 1.1 thorpej */ 1498 1.1 thorpej } 1499 1.1 thorpej 1500 1.1 thorpej /* 1501 1.1 thorpej * cztty_diag: 1502 1.1 thorpej * 1503 1.1 thorpej * Issue a scheduled diagnostic message. 1504 1.1 thorpej */ 1505 1.32 thorpej static void 1506 1.1 thorpej cztty_diag(void *arg) 1507 1.1 thorpej { 1508 1.1 thorpej struct cztty_softc *sc = arg; 1509 1.1 thorpej struct cz_softc *cz = CZTTY_CZ(sc); 1510 1.1 thorpej u_int overflows, parity_errors, framing_errors; 1511 1.1 thorpej int s; 1512 1.1 thorpej 1513 1.1 thorpej s = spltty(); 1514 1.1 thorpej 1515 1.1 thorpej overflows = sc->sc_overflows; 1516 1.1 thorpej sc->sc_overflows = 0; 1517 1.1 thorpej 1518 1.1 thorpej parity_errors = sc->sc_parity_errors; 1519 1.1 thorpej sc->sc_parity_errors = 0; 1520 1.1 thorpej 1521 1.1 thorpej framing_errors = sc->sc_framing_errors; 1522 1.1 thorpej sc->sc_framing_errors = 0; 1523 1.1 thorpej 1524 1.1 thorpej sc->sc_errors = 0; 1525 1.1 thorpej 1526 1.1 thorpej splx(s); 1527 1.1 thorpej 1528 1.1 thorpej log(LOG_WARNING, 1529 1.1 thorpej "%s: channel %d: %u overflow%s, %u parity, %u framing error%s\n", 1530 1.56 chs device_xname(cz->cz_dev), sc->sc_channel, 1531 1.1 thorpej overflows, overflows == 1 ? "" : "s", 1532 1.1 thorpej parity_errors, 1533 1.1 thorpej framing_errors, framing_errors == 1 ? "" : "s"); 1534 1.1 thorpej } 1535 1.1 thorpej 1536 1.32 thorpej const struct cdevsw cz_cdevsw = { 1537 1.58 dholland .d_open = czttyopen, 1538 1.58 dholland .d_close = czttyclose, 1539 1.58 dholland .d_read = czttyread, 1540 1.58 dholland .d_write = czttywrite, 1541 1.58 dholland .d_ioctl = czttyioctl, 1542 1.58 dholland .d_stop = czttystop, 1543 1.58 dholland .d_tty = czttytty, 1544 1.58 dholland .d_poll = czttypoll, 1545 1.58 dholland .d_mmap = nommap, 1546 1.58 dholland .d_kqfilter = ttykqfilter, 1547 1.60 dholland .d_discard = nodiscard, 1548 1.58 dholland .d_flag = D_TTY 1549 1.32 thorpej }; 1550 1.32 thorpej 1551 1.1 thorpej /* 1552 1.1 thorpej * tx and rx ring buffer size macros: 1553 1.1 thorpej * 1554 1.1 thorpej * The transmitter and receiver both use ring buffers. For each one, there 1555 1.1 thorpej * is a get (consumer) and a put (producer) offset. The get value is the 1556 1.1 thorpej * next byte to be read from the ring, and the put is the next one to be 1557 1.1 thorpej * put into the ring. get == put means the ring is empty. 1558 1.1 thorpej * 1559 1.1 thorpej * For each ring, the firmware controls one of (get, put) and this driver 1560 1.1 thorpej * controls the other. For transmission, this driver updates put to point 1561 1.1 thorpej * past the valid data, and the firmware moves get as bytes are sent. Likewise 1562 1.1 thorpej * for receive, the driver controls put, and this driver controls get. 1563 1.1 thorpej */ 1564 1.1 thorpej #define TX_MOVEABLE(g, p, s) (((g) > (p)) ? ((g) - (p) - 1) : ((s) - (p))) 1565 1.1 thorpej #define RX_MOVEABLE(g, p, s) (((g) > (p)) ? ((s) - (g)) : ((p) - (g))) 1566 1.1 thorpej 1567 1.1 thorpej /* 1568 1.1 thorpej * cztty_transmit() 1569 1.1 thorpej * 1570 1.1 thorpej * Look at the tty for this port and start sending. 1571 1.1 thorpej */ 1572 1.32 thorpej static int 1573 1.1 thorpej cztty_transmit(struct cztty_softc *sc, struct tty *tp) 1574 1.1 thorpej { 1575 1.1 thorpej struct cz_softc *cz = CZTTY_CZ(sc); 1576 1.1 thorpej u_int move, get, put, size, address; 1577 1.1 thorpej #ifdef HOSTRAMCODE 1578 1.1 thorpej int error, done = 0; 1579 1.1 thorpej #else 1580 1.1 thorpej int done = 0; 1581 1.1 thorpej #endif 1582 1.1 thorpej 1583 1.1 thorpej size = CZTTY_BUF_READ(sc, BUFCTL_TX_BUFSIZE); 1584 1.1 thorpej get = CZTTY_BUF_READ(sc, BUFCTL_TX_GET); 1585 1.1 thorpej put = CZTTY_BUF_READ(sc, BUFCTL_TX_PUT); 1586 1.1 thorpej address = CZTTY_BUF_READ(sc, BUFCTL_TX_BUFADDR); 1587 1.1 thorpej 1588 1.1 thorpej while ((tp->t_outq.c_cc > 0) && ((move = TX_MOVEABLE(get, put, size)))){ 1589 1.1 thorpej #ifdef HOSTRAMCODE 1590 1.1 thorpej if (0) { 1591 1.63 riastrad move = uimin(tp->t_outq.c_cc, move); 1592 1.1 thorpej error = q_to_b(&tp->t_outq, 0, move); 1593 1.1 thorpej if (error != move) { 1594 1.1 thorpej printf("%s: channel %d: error moving to " 1595 1.56 chs "transmit buf\n", device_xname(cz->cz_dev), 1596 1.1 thorpej sc->sc_channel); 1597 1.1 thorpej move = error; 1598 1.1 thorpej } 1599 1.1 thorpej } else { 1600 1.1 thorpej #endif 1601 1.63 riastrad move = uimin(ndqb(&tp->t_outq, 0), move); 1602 1.1 thorpej bus_space_write_region_1(cz->cz_win_st, cz->cz_win_sh, 1603 1.1 thorpej address + put, tp->t_outq.c_cf, move); 1604 1.1 thorpej ndflush(&tp->t_outq, move); 1605 1.1 thorpej #ifdef HOSTRAMCODE 1606 1.1 thorpej } 1607 1.1 thorpej #endif 1608 1.1 thorpej 1609 1.1 thorpej put = ((put + move) % size); 1610 1.1 thorpej done = 1; 1611 1.1 thorpej } 1612 1.1 thorpej if (done) { 1613 1.1 thorpej CZTTY_BUF_WRITE(sc, BUFCTL_TX_PUT, put); 1614 1.1 thorpej } 1615 1.1 thorpej return (done); 1616 1.1 thorpej } 1617 1.1 thorpej 1618 1.32 thorpej static int 1619 1.1 thorpej cztty_receive(struct cztty_softc *sc, struct tty *tp) 1620 1.1 thorpej { 1621 1.1 thorpej struct cz_softc *cz = CZTTY_CZ(sc); 1622 1.1 thorpej u_int get, put, size, address; 1623 1.1 thorpej int done = 0, ch; 1624 1.1 thorpej 1625 1.1 thorpej size = CZTTY_BUF_READ(sc, BUFCTL_RX_BUFSIZE); 1626 1.1 thorpej get = CZTTY_BUF_READ(sc, BUFCTL_RX_GET); 1627 1.1 thorpej put = CZTTY_BUF_READ(sc, BUFCTL_RX_PUT); 1628 1.1 thorpej address = CZTTY_BUF_READ(sc, BUFCTL_RX_BUFADDR); 1629 1.1 thorpej 1630 1.1 thorpej while ((get != put) && ((tp->t_canq.c_cc + tp->t_rawq.c_cc) < tp->t_hiwat)) { 1631 1.1 thorpej #ifdef HOSTRAMCODE 1632 1.44 garbled if (hostram) { 1633 1.1 thorpej ch = ((char *)fifoaddr)[get]; 1634 1.1 thorpej } else { 1635 1.1 thorpej #endif 1636 1.1 thorpej ch = bus_space_read_1(cz->cz_win_st, cz->cz_win_sh, 1637 1.1 thorpej address + get); 1638 1.1 thorpej #ifdef HOSTRAMCODE 1639 1.1 thorpej } 1640 1.1 thorpej #endif 1641 1.11 eeh (*tp->t_linesw->l_rint)(ch, tp); 1642 1.1 thorpej get = (get + 1) % size; 1643 1.1 thorpej done = 1; 1644 1.1 thorpej } 1645 1.1 thorpej if (done) { 1646 1.1 thorpej CZTTY_BUF_WRITE(sc, BUFCTL_RX_GET, get); 1647 1.1 thorpej } 1648 1.1 thorpej return (done); 1649 1.1 thorpej } 1650