1 /* $NetBSD: sunkbd.c,v 1.32 2022/10/26 23:47:55 riastradh 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 tty (line discipline). 45 * This driver uses kbdsun middle layer to hook up to /dev/kbd. 46 */ 47 48 /* 49 * Keyboard interface line discipline. 50 * 51 */ 52 53 #include <sys/cdefs.h> 54 __KERNEL_RCSID(0, "$NetBSD: sunkbd.c,v 1.32 2022/10/26 23:47:55 riastradh Exp $"); 55 56 #include <sys/param.h> 57 #include <sys/systm.h> 58 #include <sys/conf.h> 59 #include <sys/device.h> 60 #include <sys/kernel.h> 61 #include <sys/proc.h> 62 #include <sys/signal.h> 63 #include <sys/signalvar.h> 64 #include <sys/time.h> 65 #include <sys/select.h> 66 #include <sys/syslog.h> 67 #include <sys/fcntl.h> 68 #include <sys/tty.h> 69 70 #include <dev/cons.h> 71 #include <machine/vuid_event.h> 72 #include <machine/kbd.h> 73 #include <dev/sun/event_var.h> 74 #include <dev/sun/kbd_xlate.h> 75 #include <dev/sun/kbdvar.h> 76 #include <dev/sun/kbdsunvar.h> 77 #include <dev/sun/kbd_ms_ttyvar.h> 78 79 /**************************************************************** 80 * Interface to the lower layer (ttycc) 81 ****************************************************************/ 82 83 static int sunkbd_match(device_t, cfdata_t, void *); 84 static void sunkbd_attach(device_t, device_t, void *); 85 static void sunkbd_write_data(struct kbd_sun_softc *, int); 86 static int sunkbdiopen(device_t, int mode); 87 88 #if NWSKBD > 0 89 void kbd_wskbd_attach(struct kbd_softc *k, int isconsole); 90 #endif 91 92 int sunkbdinput(int, struct tty *); 93 int sunkbdstart(struct tty *); 94 95 /* Default keyboard baud rate */ 96 int sunkbd_bps = KBD_DEFAULT_BPS; 97 98 CFATTACH_DECL_NEW(kbd_tty, sizeof(struct kbd_sun_softc), 99 sunkbd_match, sunkbd_attach, NULL, NULL); 100 101 struct linesw sunkbd_disc = { 102 .l_name = "sunkbd", 103 .l_open = ttylopen, 104 .l_close = ttylclose, 105 .l_read = ttyerrio, 106 .l_write = ttyerrio, 107 .l_ioctl = ttynullioctl, 108 .l_rint = sunkbdinput, 109 .l_start = sunkbdstart, 110 .l_modem = nullmodem, 111 .l_poll = ttpoll 112 }; 113 114 115 /* 116 * sunkbd_match: how is this tty channel configured? 117 */ 118 int 119 sunkbd_match(device_t parent, cfdata_t cf, void *aux) 120 { 121 struct kbd_ms_tty_attach_args *args = aux; 122 123 if (strcmp(args->kmta_name, "keyboard") == 0) 124 return 1; 125 126 return 0; 127 } 128 129 void 130 sunkbd_attach(device_t parent, device_t self, void *aux) 131 { 132 struct kbd_sun_softc *k = device_private(self); 133 struct kbd_ms_tty_attach_args *args = aux; 134 struct tty *tp = args->kmta_tp; 135 struct cons_channel *cc; 136 137 k->k_kbd.k_dev = self; 138 139 /* Set up the proper line discipline. */ 140 if (ttyldisc_attach(&sunkbd_disc) != 0) 141 panic("sunkbd_attach: sunkbd_disc"); 142 ttyldisc_release(tp->t_linesw); 143 tp->t_linesw = ttyldisc_lookup(sunkbd_disc.l_name); 144 KASSERT(tp->t_linesw == &sunkbd_disc); 145 tp->t_oflag &= ~OPOST; 146 tp->t_dev = args->kmta_dev; 147 SET(tp->t_state, TS_KERN_ONLY); 148 149 /* link the structures together. */ 150 k->k_priv = tp; 151 tp->t_sc = k; 152 153 /* provide our middle layer with a link to the lower layer (i.e. us) */ 154 k->k_deviopen = sunkbdiopen; 155 k->k_deviclose = NULL; 156 k->k_write_data = sunkbd_write_data; 157 158 /* provide upper layer with a link to our middle layer */ 159 k->k_kbd.k_ops = &kbd_ops_sun; 160 161 /* alloc console input channel */ 162 if ((cc = kbd_cc_alloc(&k->k_kbd)) == NULL) 163 return; 164 165 if (args->kmta_consdev) { 166 char magic[4]; 167 168 /* 169 * Hookup ourselves as the console input channel 170 */ 171 args->kmta_baud = sunkbd_bps; 172 args->kmta_cflag = CLOCAL|CS8; 173 cons_attach_input(cc, args->kmta_consdev); 174 175 /* Tell our parent what the console should be. */ 176 args->kmta_consdev = cn_tab; 177 k->k_kbd.k_isconsole = 1; 178 aprint_normal(" (console input)"); 179 180 /* Set magic to "L1-A" */ 181 magic[0] = KBD_L1; 182 magic[1] = KBD_A; 183 magic[2] = 0; 184 cn_set_magic(magic); 185 } else { 186 extern void kd_attach_input(struct cons_channel *); 187 188 kd_attach_input(cc); 189 } 190 191 192 aprint_normal("\n"); 193 194 #if NWSKBD > 0 195 kbd_wskbd_attach(&k->k_kbd, args->kmta_consdev != NULL); 196 #endif 197 198 /* Do this before any calls to kbd_rint(). */ 199 kbd_xlate_init(&k->k_kbd.k_state); 200 201 /* Magic sequence. */ 202 k->k_magic1 = KBD_L1; 203 k->k_magic2 = KBD_A; 204 } 205 206 /* 207 * Internal open routine. This really should be inside com.c 208 * But I'm putting it here until we have a generic internal open 209 * mechanism. 210 */ 211 int 212 sunkbdiopen(device_t dev, int flags) 213 { 214 struct kbd_sun_softc *k = device_private(dev); 215 struct tty *tp = k->k_priv; 216 struct lwp *l = curlwp ? curlwp : &lwp0; 217 struct termios t; 218 int error; 219 220 /* Open the lower device */ 221 CLR(tp->t_state, TS_KERN_ONLY); 222 if ((error = cdev_open(tp->t_dev, O_NONBLOCK|flags, 223 0/* ignored? */, l)) != 0) 224 return (error); 225 226 /* Now configure it for the console. */ 227 tp->t_ospeed = 0; 228 t.c_ispeed = sunkbd_bps; 229 t.c_ospeed = sunkbd_bps; 230 t.c_cflag = CLOCAL|CS8; 231 (*tp->t_param)(tp, &t); 232 SET(tp->t_state, TS_KERN_ONLY); 233 234 return (0); 235 } 236 237 /* 238 * TTY interface to handle input. 239 */ 240 int 241 sunkbdinput(int c, struct tty *tp) 242 { 243 struct kbd_sun_softc *k = tp->t_sc; 244 int error; 245 246 /* 247 * Handle exceptional conditions (break, parity, framing). 248 */ 249 if ((error = ((c & TTY_ERRORMASK))) != 0) { 250 /* 251 * After garbage, flush pending input, and 252 * send a reset to resync key translation. 253 */ 254 log(LOG_ERR, "%s: input error (0x%x)\n", 255 device_xname(k->k_kbd.k_dev), c); 256 c &= TTY_CHARMASK; 257 if (!(k->k_txflags & K_TXBUSY)) { 258 ttyflush(tp, FREAD | FWRITE); 259 goto send_reset; 260 } 261 } 262 263 /* 264 * Check for input buffer overflow 265 */ 266 if (tp->t_rawq.c_cc + tp->t_canq.c_cc >= TTYHOG) { 267 log(LOG_ERR, "%s: input overrun\n", 268 device_xname(k->k_kbd.k_dev)); 269 goto send_reset; 270 } 271 272 /* Pass this up to the "middle" layer. */ 273 return(kbd_sun_input(k, c)); 274 275 send_reset: 276 /* Send a reset to resync translation. */ 277 kbd_sun_output(k, KBD_CMD_RESET); 278 return (ttstart(tp)); 279 280 } 281 282 int 283 sunkbdstart(struct tty *tp) 284 { 285 struct kbd_sun_softc *k = tp->t_sc; 286 287 /* 288 * Transmit done. Try to send more, or 289 * clear busy and wakeup drain waiters. 290 */ 291 k->k_txflags &= ~K_TXBUSY; 292 kbd_sun_start_tx(k); 293 ttstart(tp); 294 return (0); 295 } 296 /* 297 * used by kbd_sun_start_tx(); 298 */ 299 void 300 sunkbd_write_data(struct kbd_sun_softc *k, int c) 301 { 302 struct tty *tp = k->k_priv; 303 304 ttylock(tp); 305 ttyoutput(c, tp); 306 ttstart(tp); 307 ttyunlock(tp); 308 } 309