1 1.24 thorpej /* $NetBSD: kbd_zs.c,v 1.24 2022/09/25 21:30:29 thorpej Exp $ */ 2 1.1 mrg 3 1.1 mrg /* 4 1.1 mrg * Copyright (c) 1992, 1993 5 1.1 mrg * The Regents of the University of California. All rights reserved. 6 1.1 mrg * 7 1.1 mrg * This software was developed by the Computer Systems Engineering group 8 1.1 mrg * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 9 1.1 mrg * contributed to Berkeley. 10 1.1 mrg * 11 1.1 mrg * All advertising materials mentioning features or use of this software 12 1.1 mrg * must display the following acknowledgement: 13 1.1 mrg * This product includes software developed by the University of 14 1.1 mrg * California, Lawrence Berkeley Laboratory. 15 1.1 mrg * 16 1.1 mrg * Redistribution and use in source and binary forms, with or without 17 1.1 mrg * modification, are permitted provided that the following conditions 18 1.1 mrg * are met: 19 1.1 mrg * 1. Redistributions of source code must retain the above copyright 20 1.1 mrg * notice, this list of conditions and the following disclaimer. 21 1.1 mrg * 2. Redistributions in binary form must reproduce the above copyright 22 1.1 mrg * notice, this list of conditions and the following disclaimer in the 23 1.1 mrg * documentation and/or other materials provided with the distribution. 24 1.16 agc * 3. Neither the name of the University nor the names of its contributors 25 1.1 mrg * may be used to endorse or promote products derived from this software 26 1.1 mrg * without specific prior written permission. 27 1.1 mrg * 28 1.1 mrg * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 1.1 mrg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 1.1 mrg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 1.1 mrg * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 1.1 mrg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 1.1 mrg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 1.1 mrg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 1.1 mrg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 1.1 mrg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 1.1 mrg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 1.1 mrg * SUCH DAMAGE. 39 1.1 mrg * 40 1.1 mrg * @(#)kbd.c 8.2 (Berkeley) 10/30/93 41 1.1 mrg */ 42 1.1 mrg 43 1.1 mrg /* 44 1.14 uwe * /dev/kbd lower layer for sun keyboard off a zs channel. 45 1.14 uwe * This driver uses kbdsun middle layer to hook up to /dev/kbd. 46 1.1 mrg */ 47 1.1 mrg 48 1.1 mrg /* 49 1.1 mrg * Zilog Z8530 Dual UART driver (keyboard interface) 50 1.1 mrg * 51 1.1 mrg * This is the 8530 portion of the driver that will be attached to 52 1.1 mrg * the "zsc" driver for a Sun keyboard. 53 1.1 mrg */ 54 1.9 lukem 55 1.9 lukem #include <sys/cdefs.h> 56 1.24 thorpej __KERNEL_RCSID(0, "$NetBSD: kbd_zs.c,v 1.24 2022/09/25 21:30:29 thorpej Exp $"); 57 1.1 mrg 58 1.1 mrg #include <sys/param.h> 59 1.1 mrg #include <sys/systm.h> 60 1.1 mrg #include <sys/conf.h> 61 1.1 mrg #include <sys/device.h> 62 1.1 mrg #include <sys/kernel.h> 63 1.1 mrg #include <sys/proc.h> 64 1.1 mrg #include <sys/signal.h> 65 1.1 mrg #include <sys/signalvar.h> 66 1.1 mrg #include <sys/time.h> 67 1.1 mrg #include <sys/select.h> 68 1.1 mrg #include <sys/syslog.h> 69 1.1 mrg 70 1.1 mrg #include <dev/ic/z8530reg.h> 71 1.1 mrg #include <machine/z8530var.h> 72 1.15 uwe #include <dev/sun/vuid_event.h> 73 1.1 mrg #include <dev/sun/event_var.h> 74 1.15 uwe #include <dev/sun/kbd_reg.h> 75 1.1 mrg #include <dev/sun/kbd_xlate.h> 76 1.1 mrg #include <dev/sun/kbdvar.h> 77 1.14 uwe #include <dev/sun/kbdsunvar.h> 78 1.1 mrg 79 1.19 martin #if NWSKBD > 0 80 1.19 martin void kbd_wskbd_attach(struct kbd_softc *k, int isconsole); 81 1.19 martin #endif 82 1.15 uwe 83 1.1 mrg /**************************************************************** 84 1.1 mrg * Interface to the lower layer (zscc) 85 1.1 mrg ****************************************************************/ 86 1.1 mrg 87 1.17 perry static void kbd_zs_rxint(struct zs_chanstate *); 88 1.17 perry static void kbd_zs_stint(struct zs_chanstate *, int); 89 1.17 perry static void kbd_zs_txint(struct zs_chanstate *); 90 1.17 perry static void kbd_zs_softint(struct zs_chanstate *); 91 1.1 mrg 92 1.1 mrg struct zsops zsops_kbd = { 93 1.1 mrg kbd_zs_rxint, /* receive char available */ 94 1.1 mrg kbd_zs_stint, /* external/status */ 95 1.1 mrg kbd_zs_txint, /* xmit buffer empty */ 96 1.1 mrg kbd_zs_softint, /* process software interrupt */ 97 1.1 mrg }; 98 1.1 mrg 99 1.22 tsutsui static int kbd_zs_match(device_t, cfdata_t, void *); 100 1.22 tsutsui static void kbd_zs_attach(device_t, device_t, void *); 101 1.17 perry static void kbd_zs_write_data(struct kbd_sun_softc *, int); 102 1.1 mrg 103 1.22 tsutsui CFATTACH_DECL_NEW(kbd_zs, sizeof(struct kbd_sun_softc), 104 1.13 thorpej kbd_zs_match, kbd_zs_attach, NULL, NULL); 105 1.1 mrg 106 1.8 pk /* Fall-back baud rate */ 107 1.10 pk int kbd_zs_bps = KBD_DEFAULT_BPS; 108 1.8 pk 109 1.1 mrg /* 110 1.1 mrg * kbd_zs_match: how is this zs channel configured? 111 1.1 mrg */ 112 1.18 perry int 113 1.22 tsutsui kbd_zs_match(device_t parent, cfdata_t cf, void *aux) 114 1.1 mrg { 115 1.1 mrg struct zsc_attach_args *args = aux; 116 1.1 mrg 117 1.1 mrg /* Exact match required for keyboard. */ 118 1.1 mrg if (cf->cf_loc[ZSCCF_CHANNEL] == args->channel) 119 1.1 mrg return 2; 120 1.1 mrg 121 1.1 mrg return 0; 122 1.1 mrg } 123 1.1 mrg 124 1.18 perry void 125 1.22 tsutsui kbd_zs_attach(device_t parent, device_t self, void *aux) 126 1.1 mrg { 127 1.22 tsutsui struct kbd_sun_softc *k = device_private(self); 128 1.21 thorpej struct zsc_softc *zsc = device_private(parent); 129 1.1 mrg struct zsc_attach_args *args = aux; 130 1.1 mrg struct zs_chanstate *cs; 131 1.14 uwe int channel; 132 1.1 mrg int reset, s; 133 1.8 pk int bps; 134 1.1 mrg 135 1.22 tsutsui k->k_kbd.k_dev = self; 136 1.22 tsutsui 137 1.14 uwe /* provide upper layer with a link to the middle layer */ 138 1.14 uwe k->k_kbd.k_ops = &kbd_ops_sun; 139 1.14 uwe 140 1.14 uwe /* provide middle layer with a link to the lower layer (i.e. us) */ 141 1.1 mrg channel = args->channel; 142 1.1 mrg cs = zsc->zsc_cs[channel]; 143 1.1 mrg cs->cs_private = k; 144 1.1 mrg cs->cs_ops = &zsops_kbd; 145 1.1 mrg k->k_cs = cs; 146 1.1 mrg k->k_write_data = kbd_zs_write_data; 147 1.14 uwe 148 1.8 pk if ((bps = cs->cs_defspeed) == 0) 149 1.8 pk bps = kbd_zs_bps; 150 1.8 pk 151 1.22 tsutsui aprint_normal(": baud rate %d", bps); 152 1.1 mrg 153 1.2 pk if ((args->hwflags & ZS_HWFLAG_CONSOLE_INPUT) != 0) { 154 1.2 pk /* 155 1.2 pk * Hookup ourselves as the console input channel 156 1.2 pk */ 157 1.15 uwe struct cons_channel *cc = kbd_cc_alloc(&k->k_kbd); 158 1.2 pk 159 1.15 uwe if (cc == NULL) 160 1.2 pk return; 161 1.2 pk 162 1.6 eeh cons_attach_input(cc, args->consdev); 163 1.14 uwe k->k_kbd.k_isconsole = 1; 164 1.22 tsutsui aprint_normal(" (console input)"); 165 1.1 mrg } 166 1.22 tsutsui aprint_normal("\n"); 167 1.4 thorpej 168 1.1 mrg /* Initialize the speed, etc. */ 169 1.1 mrg s = splzs(); 170 1.14 uwe if (k->k_kbd.k_isconsole == 0) { 171 1.1 mrg /* Not the console; may need reset. */ 172 1.1 mrg reset = (channel == 0) ? 173 1.23 tsutsui ZSWR9_A_RESET : ZSWR9_B_RESET; 174 1.1 mrg zs_write_reg(cs, 9, reset); 175 1.1 mrg } 176 1.1 mrg /* These are OK as set by zscc: WR3, WR4, WR5 */ 177 1.1 mrg /* We don't care about status interrupts. */ 178 1.1 mrg cs->cs_preg[1] = ZSWR1_RIE | ZSWR1_TIE; 179 1.8 pk (void) zs_set_speed(cs, bps); 180 1.1 mrg zs_loadchannelregs(cs); 181 1.1 mrg splx(s); 182 1.1 mrg 183 1.1 mrg /* Do this before any calls to kbd_rint(). */ 184 1.14 uwe kbd_xlate_init(&k->k_kbd.k_state); 185 1.1 mrg 186 1.1 mrg /* Magic sequence. */ 187 1.1 mrg k->k_magic1 = KBD_L1; 188 1.1 mrg k->k_magic2 = KBD_A; 189 1.19 martin #if NWSKBD > 0 190 1.19 martin kbd_wskbd_attach(&k->k_kbd, k->k_kbd.k_isconsole); 191 1.19 martin #endif 192 1.1 mrg } 193 1.1 mrg 194 1.1 mrg /* 195 1.14 uwe * used by kbd_sun_start_tx(); 196 1.1 mrg */ 197 1.1 mrg void 198 1.23 tsutsui kbd_zs_write_data(struct kbd_sun_softc *k, int c) 199 1.1 mrg { 200 1.23 tsutsui int s; 201 1.1 mrg 202 1.1 mrg /* Need splzs to avoid interruption of the delay. */ 203 1.1 mrg s = splzs(); 204 1.1 mrg zs_write_data(k->k_cs, c); 205 1.1 mrg splx(s); 206 1.1 mrg } 207 1.1 mrg 208 1.1 mrg static void 209 1.22 tsutsui kbd_zs_rxint(struct zs_chanstate *cs) 210 1.1 mrg { 211 1.14 uwe struct kbd_sun_softc *k; 212 1.5 augustss int put, put_next; 213 1.23 tsutsui uint8_t c, rr1; 214 1.1 mrg 215 1.1 mrg k = cs->cs_private; 216 1.1 mrg put = k->k_rbput; 217 1.1 mrg 218 1.1 mrg /* 219 1.1 mrg * First read the status, because reading the received char 220 1.1 mrg * destroys the status of this char. 221 1.1 mrg */ 222 1.1 mrg rr1 = zs_read_reg(cs, 1); 223 1.1 mrg c = zs_read_data(cs); 224 1.1 mrg 225 1.1 mrg if (rr1 & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) { 226 1.1 mrg /* Clear the receive error. */ 227 1.1 mrg zs_write_csr(cs, ZSWR0_RESET_ERRORS); 228 1.1 mrg } 229 1.1 mrg 230 1.1 mrg /* 231 1.1 mrg * Check NOW for a console abort sequence, so that we can 232 1.1 mrg * abort even when interrupts are locking up the machine. 233 1.1 mrg */ 234 1.1 mrg if (k->k_magic1_down) { 235 1.1 mrg /* The last keycode was "MAGIC1" down. */ 236 1.1 mrg k->k_magic1_down = 0; 237 1.1 mrg if (c == k->k_magic2) { 238 1.1 mrg /* Magic "L1-A" sequence; enter debugger. */ 239 1.14 uwe if (k->k_kbd.k_isconsole) { 240 1.1 mrg zs_abort(cs); 241 1.1 mrg /* Debugger done. Fake L1-up to finish it. */ 242 1.1 mrg c = k->k_magic1 | KBD_UP; 243 1.1 mrg } else { 244 1.23 tsutsui printf("%s: magic sequence, but not console\n", 245 1.23 tsutsui device_xname(k->k_kbd.k_dev)); 246 1.1 mrg } 247 1.1 mrg } 248 1.1 mrg } 249 1.1 mrg if (c == k->k_magic1) { 250 1.1 mrg k->k_magic1_down = 1; 251 1.1 mrg } 252 1.1 mrg 253 1.1 mrg k->k_rbuf[put] = (c << 8) | rr1; 254 1.1 mrg put_next = (put + 1) & KBD_RX_RING_MASK; 255 1.1 mrg 256 1.1 mrg /* Would overrun if increment makes (put==get). */ 257 1.1 mrg if (put_next == k->k_rbget) { 258 1.1 mrg k->k_intr_flags |= INTR_RX_OVERRUN; 259 1.1 mrg } else { 260 1.1 mrg /* OK, really increment. */ 261 1.1 mrg put = put_next; 262 1.1 mrg } 263 1.1 mrg 264 1.1 mrg /* Done reading. */ 265 1.1 mrg k->k_rbput = put; 266 1.1 mrg 267 1.1 mrg /* Ask for softint() call. */ 268 1.1 mrg cs->cs_softreq = 1; 269 1.1 mrg } 270 1.1 mrg 271 1.1 mrg 272 1.1 mrg static void 273 1.22 tsutsui kbd_zs_txint(struct zs_chanstate *cs) 274 1.1 mrg { 275 1.14 uwe struct kbd_sun_softc *k; 276 1.1 mrg 277 1.1 mrg k = cs->cs_private; 278 1.1 mrg zs_write_csr(cs, ZSWR0_RESET_TXINT); 279 1.1 mrg k->k_intr_flags |= INTR_TX_EMPTY; 280 1.1 mrg /* Ask for softint() call. */ 281 1.1 mrg cs->cs_softreq = 1; 282 1.1 mrg } 283 1.1 mrg 284 1.1 mrg 285 1.1 mrg static void 286 1.22 tsutsui kbd_zs_stint(struct zs_chanstate *cs, int force) 287 1.1 mrg { 288 1.14 uwe struct kbd_sun_softc *k; 289 1.23 tsutsui uint8_t rr0; 290 1.1 mrg 291 1.1 mrg k = cs->cs_private; 292 1.1 mrg 293 1.1 mrg rr0 = zs_read_csr(cs); 294 1.1 mrg zs_write_csr(cs, ZSWR0_RESET_STATUS); 295 1.1 mrg 296 1.1 mrg #if 0 297 1.1 mrg if (rr0 & ZSRR0_BREAK) { 298 1.1 mrg /* Keyboard unplugged? */ 299 1.1 mrg zs_abort(cs); 300 1.23 tsutsui return; 301 1.1 mrg } 302 1.1 mrg #endif 303 1.1 mrg 304 1.1 mrg /* 305 1.1 mrg * We have to accumulate status line changes here. 306 1.1 mrg * Otherwise, if we get multiple status interrupts 307 1.1 mrg * before the softint runs, we could fail to notice 308 1.1 mrg * some status line changes in the softint routine. 309 1.1 mrg * Fix from Bill Studenmund, October 1996. 310 1.1 mrg */ 311 1.1 mrg cs->cs_rr0_delta |= (cs->cs_rr0 ^ rr0); 312 1.1 mrg cs->cs_rr0 = rr0; 313 1.1 mrg k->k_intr_flags |= INTR_ST_CHECK; 314 1.1 mrg 315 1.1 mrg /* Ask for softint() call. */ 316 1.1 mrg cs->cs_softreq = 1; 317 1.1 mrg } 318 1.1 mrg 319 1.1 mrg /* 320 1.7 wiz * Get input from the receive ring and pass it on. 321 1.1 mrg * Note: this is called at splsoftclock() 322 1.1 mrg */ 323 1.1 mrg static void 324 1.22 tsutsui kbd_zs_softint(struct zs_chanstate *cs) 325 1.1 mrg { 326 1.14 uwe struct kbd_sun_softc *k; 327 1.5 augustss int get, c, s; 328 1.1 mrg int intr_flags; 329 1.23 tsutsui uint16_t ring_data; 330 1.1 mrg 331 1.1 mrg k = cs->cs_private; 332 1.1 mrg 333 1.1 mrg /* Atomically get and clear flags. */ 334 1.1 mrg s = splzs(); 335 1.1 mrg intr_flags = k->k_intr_flags; 336 1.1 mrg k->k_intr_flags = 0; 337 1.1 mrg 338 1.1 mrg /* Now lower to spltty for the rest. */ 339 1.23 tsutsui (void)spltty(); 340 1.1 mrg 341 1.1 mrg /* 342 1.1 mrg * Copy data from the receive ring to the event layer. 343 1.1 mrg */ 344 1.1 mrg get = k->k_rbget; 345 1.1 mrg while (get != k->k_rbput) { 346 1.1 mrg ring_data = k->k_rbuf[get]; 347 1.1 mrg get = (get + 1) & KBD_RX_RING_MASK; 348 1.1 mrg 349 1.1 mrg /* low byte of ring_data is rr1 */ 350 1.1 mrg c = (ring_data >> 8) & 0xff; 351 1.1 mrg 352 1.1 mrg if (ring_data & ZSRR1_DO) 353 1.1 mrg intr_flags |= INTR_RX_OVERRUN; 354 1.1 mrg if (ring_data & (ZSRR1_FE | ZSRR1_PE)) { 355 1.1 mrg /* 356 1.1 mrg * After garbage, flush pending input, and 357 1.1 mrg * send a reset to resync key translation. 358 1.1 mrg */ 359 1.1 mrg log(LOG_ERR, "%s: input error (0x%x)\n", 360 1.22 tsutsui device_xname(k->k_kbd.k_dev), ring_data); 361 1.1 mrg get = k->k_rbput; /* flush */ 362 1.1 mrg goto send_reset; 363 1.1 mrg } 364 1.1 mrg 365 1.1 mrg /* Pass this up to the "middle" layer. */ 366 1.14 uwe kbd_sun_input(k, c); 367 1.1 mrg } 368 1.1 mrg if (intr_flags & INTR_RX_OVERRUN) { 369 1.1 mrg log(LOG_ERR, "%s: input overrun\n", 370 1.22 tsutsui device_xname(k->k_kbd.k_dev)); 371 1.1 mrg send_reset: 372 1.1 mrg /* Send a reset to resync translation. */ 373 1.14 uwe kbd_sun_output(k, KBD_CMD_RESET); 374 1.14 uwe kbd_sun_start_tx(k); 375 1.1 mrg } 376 1.1 mrg k->k_rbget = get; 377 1.1 mrg 378 1.1 mrg if (intr_flags & INTR_TX_EMPTY) { 379 1.1 mrg /* 380 1.1 mrg * Transmit done. Try to send more, or 381 1.1 mrg * clear busy and wakeup drain waiters. 382 1.1 mrg */ 383 1.1 mrg k->k_txflags &= ~K_TXBUSY; 384 1.14 uwe kbd_sun_start_tx(k); 385 1.1 mrg } 386 1.1 mrg 387 1.1 mrg if (intr_flags & INTR_ST_CHECK) { 388 1.1 mrg /* 389 1.1 mrg * Status line change. (Not expected.) 390 1.1 mrg */ 391 1.1 mrg log(LOG_ERR, "%s: status interrupt?\n", 392 1.22 tsutsui device_xname(k->k_kbd.k_dev)); 393 1.1 mrg cs->cs_rr0_delta = 0; 394 1.1 mrg } 395 1.1 mrg 396 1.1 mrg splx(s); 397 1.1 mrg } 398