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