1 /* $NetBSD: sunkbd.c,v 1.15 2002/10/26 19:11:13 martin 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. All advertising materials mentioning features or use of this software 25 * must display the following acknowledgement: 26 * This product includes software developed by the University of 27 * California, Berkeley and its contributors. 28 * 4. Neither the name of the University nor the names of its contributors 29 * may be used to endorse or promote products derived from this software 30 * without specific prior written permission. 31 * 32 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 34 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 35 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 36 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 40 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 41 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 42 * SUCH DAMAGE. 43 * 44 * @(#)kbd.c 8.2 (Berkeley) 10/30/93 45 */ 46 47 /* 48 * /dev/kbd lower layer for sun keyboard off a tty (line discipline). 49 * This driver uses kbdsun middle layer to hook up to /dev/kbd. 50 */ 51 52 /* 53 * Keyboard interface line discipline. 54 * 55 */ 56 57 #include <sys/cdefs.h> 58 __KERNEL_RCSID(0, "$NetBSD: sunkbd.c,v 1.15 2002/10/26 19:11:13 martin Exp $"); 59 60 #include <sys/param.h> 61 #include <sys/systm.h> 62 #include <sys/conf.h> 63 #include <sys/device.h> 64 #include <sys/kernel.h> 65 #include <sys/malloc.h> 66 #include <sys/proc.h> 67 #include <sys/signal.h> 68 #include <sys/signalvar.h> 69 #include <sys/time.h> 70 #include <sys/select.h> 71 #include <sys/syslog.h> 72 #include <sys/fcntl.h> 73 #include <sys/tty.h> 74 75 #include <dev/cons.h> 76 #include <machine/vuid_event.h> 77 #include <machine/kbd.h> 78 #include <dev/sun/event_var.h> 79 #include <dev/sun/kbd_xlate.h> 80 #include <dev/sun/kbdvar.h> 81 #include <dev/sun/kbdsunvar.h> 82 #include <dev/sun/kbd_ms_ttyvar.h> 83 84 /**************************************************************** 85 * Interface to the lower layer (ttycc) 86 ****************************************************************/ 87 88 static int sunkbd_match(struct device *, struct cfdata *, void *); 89 static void sunkbd_attach(struct device *, struct device *, void *); 90 static void sunkbd_write_data(struct kbd_sun_softc *, int); 91 static int sunkbdiopen(struct device *, int mode); 92 93 #if NWSKBD > 0 94 void kbd_wskbd_attach(struct kbd_softc *k, int isconsole); 95 #endif 96 97 int sunkbdinput(int, struct tty *); 98 int sunkbdstart(struct tty *); 99 100 /* Default keyboard baud rate */ 101 int sunkbd_bps = KBD_DEFAULT_BPS; 102 103 CFATTACH_DECL(kbd_tty, sizeof(struct kbd_sun_softc), 104 sunkbd_match, sunkbd_attach, NULL, NULL); 105 106 struct linesw sunkbd_disc = 107 { "sunkbd", 7, ttylopen, ttylclose, ttyerrio, ttyerrio, ttynullioctl, 108 sunkbdinput, sunkbdstart, nullmodem, ttpoll }; /* 7- SUNKBDDISC */ 109 110 111 /* 112 * sunkbd_match: how is this tty channel configured? 113 */ 114 int 115 sunkbd_match(parent, cf, aux) 116 struct device *parent; 117 struct cfdata *cf; 118 void *aux; 119 { 120 struct kbd_ms_tty_attach_args *args = aux; 121 122 if (strcmp(args->kmta_name, "keyboard") == 0) 123 return (1); 124 125 return 0; 126 } 127 128 void 129 sunkbd_attach(parent, self, aux) 130 struct device *parent, *self; 131 void *aux; 132 { 133 struct kbd_sun_softc *k = (void *) self; 134 struct kbd_ms_tty_attach_args *args = aux; 135 struct tty *tp = args->kmta_tp; 136 struct cons_channel *cc; 137 138 /* Set up the proper line discipline. */ 139 ttyldisc_init(); 140 if (ttyldisc_add(&sunkbd_disc, -1) == -1) 141 panic("sunkbd_attach: sunkbd_disc"); 142 tp->t_linesw = &sunkbd_disc; 143 tp->t_oflag &= ~OPOST; 144 tp->t_dev = args->kmta_dev; 145 146 /* link the structures together. */ 147 k->k_priv = tp; 148 tp->t_sc = (void *)k; 149 150 /* provide our middle layer with a link to the lower layer (i.e. us) */ 151 k->k_deviopen = sunkbdiopen; 152 k->k_deviclose = NULL; 153 k->k_write_data = sunkbd_write_data; 154 155 /* provide upper layer with a link to our middle layer */ 156 k->k_kbd.k_ops = &kbd_ops_sun; 157 158 /* alloc console input channel */ 159 if ((cc = kbd_cc_alloc(&k->k_kbd)) == NULL) 160 return; 161 162 if (args->kmta_consdev) { 163 char magic[4]; 164 165 /* 166 * Hookup ourselves as the console input channel 167 */ 168 args->kmta_baud = sunkbd_bps; 169 args->kmta_cflag = CLOCAL|CS8; 170 cons_attach_input(cc, args->kmta_consdev); 171 172 /* Tell our parent what the console should be. */ 173 args->kmta_consdev = cn_tab; 174 k->k_kbd.k_isconsole = 1; 175 printf(" (console input)"); 176 177 /* Set magic to "L1-A" */ 178 magic[0] = KBD_L1; 179 magic[1] = KBD_A; 180 magic[2] = 0; 181 cn_set_magic(magic); 182 } else { 183 extern void kd_attach_input(struct cons_channel *); 184 185 kd_attach_input(cc); 186 } 187 188 189 printf("\n"); 190 191 #if NWSKBD > 0 192 kbd_wskbd_attach(&k->k_kbd, args->kmta_consdev != NULL); 193 #endif 194 195 /* Do this before any calls to kbd_rint(). */ 196 kbd_xlate_init(&k->k_kbd.k_state); 197 198 /* Magic sequence. */ 199 k->k_magic1 = KBD_L1; 200 k->k_magic2 = KBD_A; 201 } 202 203 /* 204 * Internal open routine. This really should be inside com.c 205 * But I'm putting it here until we have a generic internal open 206 * mechanism. 207 */ 208 int 209 sunkbdiopen(dev, flags) 210 struct device *dev; 211 int flags; 212 { 213 struct kbd_sun_softc *k = (void *) dev; 214 struct tty *tp = (struct tty *)k->k_priv; 215 struct proc *p = curproc; 216 struct termios t; 217 const struct cdevsw *cdev; 218 int error; 219 220 if (p == NULL) 221 p = &proc0; 222 223 cdev = cdevsw_lookup(tp->t_dev); 224 if (cdev == NULL) 225 return (ENXIO); 226 227 /* Open the lower device */ 228 if ((error = (*cdev->d_open)(tp->t_dev, O_NONBLOCK|flags, 229 0/* ignored? */, p)) != 0) 230 return (error); 231 232 /* Now configure it for the console. */ 233 tp->t_ospeed = 0; 234 t.c_ispeed = sunkbd_bps; 235 t.c_ospeed = sunkbd_bps; 236 t.c_cflag = CLOCAL|CS8; 237 (*tp->t_param)(tp, &t); 238 239 return (0); 240 } 241 242 /* 243 * TTY interface to handle input. 244 */ 245 int 246 sunkbdinput(c, tp) 247 int c; 248 struct tty *tp; 249 { 250 struct kbd_sun_softc *k = (void *) tp->t_sc; 251 u_char *cc; 252 int error; 253 254 255 cc = tp->t_cc; 256 257 /* 258 * Handle exceptional conditions (break, parity, framing). 259 */ 260 if ((error = ((c & TTY_ERRORMASK))) != 0) { 261 /* 262 * After garbage, flush pending input, and 263 * send a reset to resync key translation. 264 */ 265 log(LOG_ERR, "%s: input error (0x%x)\n", 266 k->k_kbd.k_dev.dv_xname, c); 267 c &= TTY_CHARMASK; 268 if (!k->k_txflags & K_TXBUSY) { 269 ttyflush(tp, FREAD | FWRITE); 270 goto send_reset; 271 } 272 } 273 274 /* 275 * Check for input buffer overflow 276 */ 277 if (tp->t_rawq.c_cc + tp->t_canq.c_cc >= TTYHOG) { 278 log(LOG_ERR, "%s: input overrun\n", 279 k->k_kbd.k_dev.dv_xname); 280 goto send_reset; 281 } 282 283 /* Pass this up to the "middle" layer. */ 284 kbd_sun_input(k, c); 285 return (-1); 286 287 send_reset: 288 /* Send a reset to resync translation. */ 289 kbd_sun_output(k, KBD_CMD_RESET); 290 return (ttstart(tp)); 291 292 } 293 294 int 295 sunkbdstart(tp) 296 struct tty *tp; 297 { 298 struct kbd_sun_softc *k = (void *) tp->t_sc; 299 300 /* 301 * Transmit done. Try to send more, or 302 * clear busy and wakeup drain waiters. 303 */ 304 k->k_txflags &= ~K_TXBUSY; 305 kbd_sun_start_tx(k); 306 ttstart(tp); 307 return (0); 308 } 309 /* 310 * used by kbd_sun_start_tx(); 311 */ 312 void 313 sunkbd_write_data(k, c) 314 struct kbd_sun_softc *k; 315 int c; 316 { 317 struct tty *tp = (struct tty *)k->k_priv; 318 int s; 319 320 s = spltty(); 321 ttyoutput(c, tp); 322 ttstart(tp); 323 splx(s); 324 } 325