1 /* $NetBSD: hpf1275a_tty.c,v 1.1 2004/06/23 21:50:22 uwe Exp $ */ 2 3 /* 4 * Copyright (c) 2004 Valeriy E. Ushakov 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 __KERNEL_RCSID(0, "$NetBSD: hpf1275a_tty.c,v 1.1 2004/06/23 21:50:22 uwe Exp $"); 32 33 #include <sys/param.h> 34 #include <sys/kernel.h> 35 #include <sys/conf.h> 36 #include <sys/device.h> 37 #include <sys/tty.h> 38 #include <sys/fcntl.h> 39 #include <sys/proc.h> /* XXX: for curproc */ 40 #include <sys/systm.h> 41 #ifdef GPROF 42 #include <sys/gmon.h> 43 #endif 44 45 #include <dev/pckbport/wskbdmap_mfii.h> 46 #ifdef WSDISPLAY_COMPAT_RAWKBD 47 #include <dev/hpc/pckbd_encode.h> 48 #endif 49 50 #include <dev/wscons/wsconsio.h> 51 #include <dev/wscons/wskbdvar.h> 52 #include <dev/wscons/wsksymdef.h> 53 #include <dev/wscons/wsksymvar.h> 54 55 56 extern struct cfdriver hpf1275a_cd; 57 58 struct hpf1275a_softc { 59 struct device sc_dev; 60 61 struct tty *sc_tp; /* back reference to the tty */ 62 struct device *sc_wskbd; /* wskbd child */ 63 int sc_enabled; 64 65 }; 66 67 68 /* pseudo-device initialization */ 69 extern void hpf1275aattach(int); 70 71 /* line discipline methods */ 72 static int hpf1275a_open(dev_t, struct tty *); 73 static int hpf1275a_close(struct tty *, int); 74 static int hpf1275a_input(int, struct tty *); 75 76 /* autoconf(9) methods */ 77 static int hpf1275a_match(struct device *, struct cfdata *, void *); 78 static void hpf1275a_attach(struct device *, struct device *, void *); 79 static int hpf1275a_detach(struct device *, int); 80 81 /* wskbd(4) accessops */ 82 static int hpf1275a_wskbd_enable(void *, int); 83 static void hpf1275a_wskbd_set_leds(void *, int); 84 static int hpf1275a_wskbd_ioctl(void *, u_long, caddr_t, int, 85 struct proc *); 86 87 88 CFATTACH_DECL(hpf1275a, sizeof(struct hpf1275a_softc), 89 hpf1275a_match, hpf1275a_attach, hpf1275a_detach, NULL); 90 91 92 static struct linesw hpf1275a_disc = { 93 "hpf1275a", -1, hpf1275a_open, hpf1275a_close, 94 ttyerrio, ttyerrio, ttynullioctl, 95 hpf1275a_input, ttstart, nullmodem, ttpoll, 96 }; 97 98 99 static const struct wskbd_accessops hpf1275a_wskbd_accessops = { 100 hpf1275a_wskbd_enable, 101 hpf1275a_wskbd_set_leds, 102 hpf1275a_wskbd_ioctl 103 }; 104 105 106 static struct wskbd_mapdata hpf1275a_wskbd_keymapdata = { 107 pckbd_keydesctab, KB_US 108 }; 109 110 111 /* F1275A scancodes -> XT scancodes so that we can use pckbd_keydesctab. */ 112 static uint8_t hpf1275a_to_xtscan[128] = { 113 [0x04] = 30, /* a */ 114 [0x05] = 48, /* b */ 115 [0x06] = 46, /* c */ 116 [0x07] = 32, /* d */ 117 [0x08] = 18, /* e */ 118 [0x09] = 33, /* f */ 119 [0x0a] = 34, /* g */ 120 [0x0b] = 35, /* h */ 121 [0x0c] = 23, /* i */ 122 [0x0d] = 36, /* j */ 123 [0x0e] = 37, /* k */ 124 [0x0f] = 38, /* l */ 125 [0x10] = 50, /* m */ 126 [0x11] = 49, /* n */ 127 [0x12] = 24, /* o */ 128 [0x13] = 25, /* p */ 129 [0x14] = 16, /* q */ 130 [0x15] = 19, /* r */ 131 [0x16] = 31, /* s */ 132 [0x17] = 20, /* t */ 133 [0x18] = 22, /* u */ 134 [0x19] = 47, /* v */ 135 [0x1a] = 17, /* w */ 136 [0x1b] = 45, /* x */ 137 [0x1c] = 21, /* y */ 138 [0x1d] = 44, /* z */ 139 140 [0x1e] = 2, /* 1 */ 141 [0x1f] = 3, /* 2 */ 142 [0x20] = 4, /* 3 */ 143 [0x21] = 5, /* 4 */ 144 [0x22] = 6, /* 5 */ 145 [0x23] = 7, /* 6 */ 146 [0x24] = 8, /* 7 */ 147 [0x25] = 9, /* 8 */ 148 [0x26] = 10, /* 9 */ 149 [0x27] = 11, /* 0 */ 150 151 [0x28] = 28, /* Enter */ 152 153 [0x29] = 1, /* ESC */ 154 [0x2a] = 14, /* Backspace */ 155 [0x2b] = 15, /* Tab */ 156 [0x2c] = 57, /* Space */ 157 158 [0x2d] = 12, /* - */ 159 [0x2e] = 13, /* = */ 160 [0x2f] = 26, /* [ */ 161 [0x30] = 27, /* ] */ 162 [0x31] = 43, /* \ */ 163 164 [0x33] = 39, /* ; */ 165 [0x34] = 40, /* ' */ 166 [0x35] = 41, /* ` */ 167 [0x36] = 51, /* , */ 168 [0x37] = 52, /* . */ 169 [0x38] = 53, /* / */ 170 171 [0x3a] = 59, /* F1 */ 172 [0x3b] = 60, /* F2 */ 173 [0x3c] = 61, /* F3 */ 174 [0x3d] = 62, /* F4 */ 175 [0x3e] = 63, /* F5 */ 176 [0x3f] = 64, /* F6 */ 177 [0x40] = 65, /* F7 */ 178 [0x41] = 66, /* F8 */ 179 180 [0x42] = 68, /* "OK" -> F10 */ 181 [0x43] = 87, /* "Cancel" -> F11 */ 182 183 [0x4c] = 211, /* Del */ 184 185 [0x4f] = 205, /* Right */ 186 [0x50] = 203, /* Left */ 187 [0x51] = 208, /* Down */ 188 [0x52] = 200, /* Up */ 189 190 [0x53] = 67, /* "task switch" -> F9 */ 191 192 [0x65] = 221, /* windows */ 193 [0x66] = 88, /* "keyboard" -> F12 */ 194 195 [0x74] = 42, /* Shift (left) */ 196 [0x75] = 54, /* Shift (right) */ 197 [0x76] = 56, /* Alt (left) */ 198 [0x77] = 184, /* Fn -> AltGr == Mode Switch */ 199 [0x78] = 29, /* Control (left) */ 200 }; 201 202 203 /* 204 * Pseudo-device initialization routine called from main(). 205 */ 206 void 207 hpf1275aattach(int n) 208 { 209 int discno; 210 int error; 211 212 discno = ttyldisc_add(&hpf1275a_disc, -1); 213 if (discno < 0) { 214 printf("%s: unable to register line discipline\n", 215 hpf1275a_cd.cd_name); 216 return; 217 } 218 219 error = config_cfattach_attach(hpf1275a_cd.cd_name, &hpf1275a_ca); 220 if (error) { 221 printf("%s: unable to register cfattach, error = %d\n", 222 hpf1275a_cd.cd_name, error); 223 config_cfdriver_detach(&hpf1275a_cd); 224 ttyldisc_remove(hpf1275a_disc.l_name); 225 } 226 } 227 228 229 /* 230 * Autoconf match routine. 231 * 232 * XXX: unused: config_attach_pseudo(9) does not call ca_match. 233 */ 234 static int 235 hpf1275a_match(struct device *self, struct cfdata *cfdata, void *arg) 236 { 237 238 /* pseudo-device; always present */ 239 return (1); 240 } 241 242 243 /* 244 * Autoconf attach routine. Called by config_attach_pseudo(9) when we 245 * open the line discipline. 246 */ 247 static void 248 hpf1275a_attach(struct device *parent, struct device *self, void *aux) 249 { 250 struct hpf1275a_softc *sc = (struct hpf1275a_softc *)self; 251 struct wskbddev_attach_args wska; 252 253 wska.console = 0; 254 wska.keymap = &hpf1275a_wskbd_keymapdata; 255 wska.accessops = &hpf1275a_wskbd_accessops; 256 wska.accesscookie = sc; 257 258 sc->sc_enabled = 0; 259 sc->sc_wskbd = config_found(self, &wska, wskbddevprint); 260 } 261 262 263 /* 264 * Autoconf detach routine. Called when we close the line discipline. 265 */ 266 static int 267 hpf1275a_detach(struct device *self, int flags) 268 { 269 struct hpf1275a_softc *sc = (struct hpf1275a_softc *)self; 270 int error; 271 272 if (sc->sc_wskbd == NULL) 273 return (0); 274 275 error = config_detach(sc->sc_wskbd, 0); 276 277 return (error); 278 } 279 280 281 /* 282 * Line discipline open routine. 283 */ 284 int 285 hpf1275a_open(dev_t dev, struct tty *tp) 286 { 287 struct proc *p = curproc; /* XXX */ 288 struct hpf1275a_softc *sc; 289 int error, s; 290 291 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 292 return (error); 293 294 s = spltty(); 295 296 sc = (struct hpf1275a_softc *) 297 config_attach_pseudo("hpf1275a", DVUNIT_ANY); 298 if (sc == NULL) { 299 splx(s); 300 return (EIO); 301 } 302 303 tp->t_sc = sc; 304 sc->sc_tp = tp; 305 306 splx(s); 307 return (0); 308 } 309 310 311 /* 312 * Line discipline close routine. 313 */ 314 int 315 hpf1275a_close(struct tty *tp, int flag) 316 { 317 struct hpf1275a_softc *sc = (struct hpf1275a_softc *)tp->t_sc; 318 int s; 319 320 s = spltty(); 321 ttyflush(tp, FREAD | FWRITE); 322 tp->t_linesw = linesw[0]; /* default line discipline */ 323 if (sc != NULL) { 324 tp->t_sc = NULL; 325 if (sc->sc_tp == tp) 326 config_detach(&sc->sc_dev, 0); 327 } 328 splx(s); 329 return (0); 330 } 331 332 333 /* 334 * Feed input from the keyboard to wskbd(4). 335 */ 336 int 337 hpf1275a_input(int c, struct tty *tp) 338 { 339 struct hpf1275a_softc *sc = (struct hpf1275a_softc *)tp->t_sc; 340 int code; 341 u_int type; 342 int xtscan; 343 344 if (!sc->sc_enabled) 345 return (0); 346 347 if (c & TTY_ERRORMASK) 348 return (0); /* TODO? */ 349 350 code = c & TTY_CHARMASK; 351 if (code & 0x80) { 352 type = WSCONS_EVENT_KEY_UP; 353 code &= ~0x80; 354 } else 355 type = WSCONS_EVENT_KEY_DOWN; 356 357 xtscan = hpf1275a_to_xtscan[code]; 358 if (xtscan == 0) { 359 printf("hpf1275a: unknown code 0x%x\n", code); 360 return (0); 361 } 362 363 KASSERT(sc->sc_wskbd != NULL); 364 wskbd_input(sc->sc_wskbd, type, xtscan); 365 366 return (0); 367 } 368 369 370 static int 371 hpf1275a_wskbd_enable(void *self, int on) 372 { 373 struct hpf1275a_softc *sc = (struct hpf1275a_softc *)self; 374 375 sc->sc_enabled = on; 376 return (0); 377 } 378 379 380 /* ARGSUSED */ 381 static void 382 hpf1275a_wskbd_set_leds(void *self, int leds) 383 { 384 385 /* this keyboard has no leds; nothing to do */ 386 return; 387 } 388 389 390 static int 391 hpf1275a_wskbd_ioctl(void *self, u_long cmd, caddr_t data, int flag, 392 struct proc *p) 393 { 394 /* struct hpf1275a_softc *sc = (struct hpf1275a_softc *)self; */ 395 396 switch (cmd) { 397 case WSKBDIO_GTYPE: 398 *(int *)data = WSKBD_TYPE_HPC_KBD; /* may be use new type? */ 399 return (0); 400 401 case WSKBDIO_GETLEDS: 402 *(int *)data = 0; /* this keyboard has no leds */ 403 return (0); 404 405 default: 406 return (EPASSTHROUGH); 407 } 408 } 409