hpf1275a_tty.c revision 1.33
1/* $NetBSD: hpf1275a_tty.c,v 1.33 2023/05/10 00:09:54 riastradh 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.33 2023/05/10 00:09:54 riastradh Exp $"); 32 33#include "opt_wsdisplay_compat.h" 34 35#include <sys/param.h> 36#include <sys/kernel.h> 37#include <sys/conf.h> 38#include <sys/device.h> 39#include <sys/tty.h> 40#include <sys/fcntl.h> 41#include <sys/proc.h> 42#include <sys/systm.h> 43#include <sys/kauth.h> 44 45#include <dev/wscons/wsconsio.h> 46#include <dev/wscons/wskbdvar.h> 47#include <dev/wscons/wsksymdef.h> 48#include <dev/wscons/wsksymvar.h> 49 50#include <dev/pckbport/wskbdmap_mfii.h> 51#ifdef WSDISPLAY_COMPAT_RAWKBD 52#include <dev/hpc/pckbd_encode.h> 53#endif 54 55#include "ioconf.h" 56 57struct hpf1275a_softc { 58 device_t sc_dev; 59 60 struct tty *sc_tp; /* back reference to the tty */ 61 device_t sc_wskbd; /* wskbd child */ 62 int sc_enabled; 63#ifdef WSDISPLAY_COMPAT_RAWKBD 64 int sc_rawkbd; 65#endif 66}; 67 68 69/* pseudo-device initialization */ 70extern void hpf1275aattach(int); 71 72/* line discipline methods */ 73static int hpf1275a_open(dev_t, struct tty *); 74static int hpf1275a_close(struct tty *, int); 75static int hpf1275a_input(int, struct tty *); 76 77/* autoconf(9) methods */ 78static int hpf1275a_match(device_t, cfdata_t, void *); 79static void hpf1275a_attach(device_t, device_t, void *); 80static int hpf1275a_detach(device_t, int); 81 82/* wskbd(4) accessops */ 83static int hpf1275a_wskbd_enable(void *, int); 84static void hpf1275a_wskbd_set_leds(void *, int); 85static int hpf1275a_wskbd_ioctl(void *, u_long, void *, int, 86 struct lwp *); 87 88 89/* 90 * It doesn't need to be exported, as only hpf1275aattach() uses it, 91 * but there's no "official" way to make it static. 92 */ 93CFATTACH_DECL_NEW(hpf1275a, sizeof(struct hpf1275a_softc), 94 hpf1275a_match, hpf1275a_attach, hpf1275a_detach, NULL); 95 96 97static struct linesw hpf1275a_disc = { 98 .l_name = "hpf1275a", 99 .l_open = hpf1275a_open, 100 .l_close = hpf1275a_close, 101 .l_read = ttyerrio, 102 .l_write = ttyerrio, 103 .l_ioctl = ttynullioctl, 104 .l_rint = hpf1275a_input, 105 .l_start = ttstart, 106 .l_modem = nullmodem, 107 .l_poll = ttpoll 108}; 109 110 111static const struct wskbd_accessops hpf1275a_wskbd_accessops = { 112 hpf1275a_wskbd_enable, 113 hpf1275a_wskbd_set_leds, 114 hpf1275a_wskbd_ioctl 115}; 116 117 118static const struct wskbd_mapdata hpf1275a_wskbd_keymapdata = { 119 pckbd_keydesctab, KB_US 120}; 121 122 123/* F1275A scancodes -> XT scancodes so that we can use pckbd_keydesctab. */ 124static const uint8_t hpf1275a_to_xtscan[128] = { 125 [0x04] = 30, /* a */ 126 [0x05] = 48, /* b */ 127 [0x06] = 46, /* c */ 128 [0x07] = 32, /* d */ 129 [0x08] = 18, /* e */ 130 [0x09] = 33, /* f */ 131 [0x0a] = 34, /* g */ 132 [0x0b] = 35, /* h */ 133 [0x0c] = 23, /* i */ 134 [0x0d] = 36, /* j */ 135 [0x0e] = 37, /* k */ 136 [0x0f] = 38, /* l */ 137 [0x10] = 50, /* m */ 138 [0x11] = 49, /* n */ 139 [0x12] = 24, /* o */ 140 [0x13] = 25, /* p */ 141 [0x14] = 16, /* q */ 142 [0x15] = 19, /* r */ 143 [0x16] = 31, /* s */ 144 [0x17] = 20, /* t */ 145 [0x18] = 22, /* u */ 146 [0x19] = 47, /* v */ 147 [0x1a] = 17, /* w */ 148 [0x1b] = 45, /* x */ 149 [0x1c] = 21, /* y */ 150 [0x1d] = 44, /* z */ 151 152 [0x1e] = 2, /* 1 */ 153 [0x1f] = 3, /* 2 */ 154 [0x20] = 4, /* 3 */ 155 [0x21] = 5, /* 4 */ 156 [0x22] = 6, /* 5 */ 157 [0x23] = 7, /* 6 */ 158 [0x24] = 8, /* 7 */ 159 [0x25] = 9, /* 8 */ 160 [0x26] = 10, /* 9 */ 161 [0x27] = 11, /* 0 */ 162 163 [0x28] = 28, /* Enter */ 164 165 [0x29] = 1, /* ESC */ 166 [0x2a] = 14, /* Backspace */ 167 [0x2b] = 15, /* Tab */ 168 [0x2c] = 57, /* Space */ 169 170 [0x2d] = 12, /* - */ 171 [0x2e] = 13, /* = */ 172 [0x2f] = 26, /* [ */ 173 [0x30] = 27, /* ] */ 174 [0x31] = 43, /* \ */ 175 176 [0x33] = 39, /* ; */ 177 [0x34] = 40, /* ' */ 178 [0x35] = 41, /* ` */ 179 [0x36] = 51, /* , */ 180 [0x37] = 52, /* . */ 181 [0x38] = 53, /* / */ 182 183 [0x3a] = 59, /* F1 */ 184 [0x3b] = 60, /* F2 */ 185 [0x3c] = 61, /* F3 */ 186 [0x3d] = 62, /* F4 */ 187 [0x3e] = 63, /* F5 */ 188 [0x3f] = 64, /* F6 */ 189 [0x40] = 65, /* F7 */ 190 [0x41] = 66, /* F8 */ 191 192 [0x42] = 68, /* "OK" -> F10 */ 193 [0x43] = 87, /* "Cancel" -> F11 */ 194 195 [0x4c] = 211, /* Del */ 196 197 [0x4f] = 205, /* Right */ 198 [0x50] = 203, /* Left */ 199 [0x51] = 208, /* Down */ 200 [0x52] = 200, /* Up */ 201 202 [0x53] = 67, /* "task switch" -> F9 */ 203 204 [0x65] = 221, /* windows */ 205 [0x66] = 88, /* "keyboard" -> F12 */ 206 207 [0x74] = 42, /* Shift (left) */ 208 [0x75] = 54, /* Shift (right) */ 209 [0x76] = 56, /* Alt (left) */ 210 [0x77] = 184, /* Fn -> AltGr == Mode Switch */ 211 [0x78] = 29, /* Control (left) */ 212}; 213 214 215/* 216 * Pseudo-device initialization routine called from main(). 217 */ 218void 219hpf1275aattach(int n) 220{ 221 int error; 222 223 error = ttyldisc_attach(&hpf1275a_disc); 224 if (error) { 225 printf("%s: unable to register line discipline, error = %d\n", 226 hpf1275a_cd.cd_name, error); 227 return; 228 } 229 230 error = config_cfattach_attach(hpf1275a_cd.cd_name, &hpf1275a_ca); 231 if (error) { 232 printf("%s: unable to register cfattach, error = %d\n", 233 hpf1275a_cd.cd_name, error); 234 config_cfdriver_detach(&hpf1275a_cd); 235 (void) ttyldisc_detach(&hpf1275a_disc); 236 } 237} 238 239 240/* 241 * Autoconf match routine. 242 * 243 * XXX: unused: config_attach_pseudo(9) does not call ca_match. 244 */ 245static int 246hpf1275a_match(device_t self, cfdata_t cfdata, void *arg) 247{ 248 249 /* pseudo-device; always present */ 250 return (1); 251} 252 253 254/* 255 * Autoconf attach routine. Called by config_attach_pseudo(9) when we 256 * open the line discipline. 257 */ 258static void 259hpf1275a_attach(device_t parent, device_t self, void *aux) 260{ 261 struct hpf1275a_softc *sc = device_private(self); 262 struct wskbddev_attach_args wska; 263 264 wska.console = 0; 265 wska.keymap = &hpf1275a_wskbd_keymapdata; 266 wska.accessops = &hpf1275a_wskbd_accessops; 267 wska.accesscookie = sc; 268 269 sc->sc_dev = self; 270 sc->sc_enabled = 0; 271#ifdef WSDISPLAY_COMPAT_RAWKBD 272 sc->sc_rawkbd = 0; 273#endif 274 sc->sc_wskbd = config_found(self, &wska, wskbddevprint, CFARGS_NONE); 275} 276 277 278/* 279 * Autoconf detach routine. Called when we close the line discipline. 280 */ 281static int 282hpf1275a_detach(device_t self, int flags) 283{ 284 struct hpf1275a_softc *sc = device_private(self); 285 int error; 286 287 error = config_detach_children(self, flags); 288 if (error) 289 return error; 290 291 return 0; 292} 293 294 295/* 296 * Line discipline open routine. 297 */ 298static int 299hpf1275a_open(dev_t dev, struct tty *tp) 300{ 301 static struct cfdata hpf1275a_cfdata = { 302 .cf_name = "hpf1275a", 303 .cf_atname = "hpf1275a", 304 .cf_unit = 0, 305 .cf_fstate = FSTATE_STAR, 306 }; 307 struct lwp *l = curlwp; /* XXX */ 308 struct hpf1275a_softc *sc; 309 device_t self; 310 int error, s; 311 312 if ((error = kauth_authorize_device_tty(l->l_cred, 313 KAUTH_DEVICE_TTY_OPEN, tp))) 314 return (error); 315 316 s = spltty(); 317 318 if (tp->t_linesw == &hpf1275a_disc) { 319 splx(s); 320 return 0; 321 } 322 323 self = config_attach_pseudo(&hpf1275a_cfdata); 324 if (self == NULL) { 325 splx(s); 326 return (EIO); 327 } 328 329 sc = device_private(self); 330 tp->t_sc = sc; 331 sc->sc_tp = tp; 332 333 splx(s); 334 return (0); 335} 336 337 338/* 339 * Line discipline close routine. 340 */ 341static int 342hpf1275a_close(struct tty *tp, int flag) 343{ 344 struct hpf1275a_softc *sc = tp->t_sc; 345 int s; 346 347 s = spltty(); 348 ttylock(tp); 349 ttyflush(tp, FREAD | FWRITE); 350 ttyunlock(tp); /* XXX */ 351 ttyldisc_release(tp->t_linesw); 352 tp->t_linesw = ttyldisc_default(); 353 if (sc != NULL) { 354 tp->t_sc = NULL; 355 if (sc->sc_tp == tp) 356 config_detach(sc->sc_dev, 0); 357 } 358 splx(s); 359 return (0); 360} 361 362 363/* 364 * Feed input from the keyboard to wskbd(4). 365 */ 366static int 367hpf1275a_input(int c, struct tty *tp) 368{ 369 struct hpf1275a_softc *sc = tp->t_sc; 370 int code; 371 u_int type; 372 int xtscan; 373 374 if (!sc->sc_enabled) 375 return (0); 376 377 if (c & TTY_ERRORMASK) 378 return (0); /* TODO? */ 379 380 code = c & TTY_CHARMASK; 381 if (code & 0x80) { 382 type = WSCONS_EVENT_KEY_UP; 383 code &= ~0x80; 384 } else 385 type = WSCONS_EVENT_KEY_DOWN; 386 387 xtscan = hpf1275a_to_xtscan[code]; 388 if (xtscan == 0) { 389 aprint_error_dev(sc->sc_dev, "unknown code 0x%x\n", code); 390 return (0); 391 } 392 393 KASSERT(sc->sc_wskbd != NULL); 394 395#ifdef WSDISPLAY_COMPAT_RAWKBD 396 if (sc->sc_rawkbd) { 397 u_char data[16]; 398 int n; 399 400 n = pckbd_encode(type, xtscan, data); 401 wskbd_rawinput(sc->sc_wskbd, data, n); 402 } else 403#endif 404 wskbd_input(sc->sc_wskbd, type, xtscan); 405 406 return (0); 407} 408 409 410static int 411hpf1275a_wskbd_enable(void *self, int on) 412{ 413 struct hpf1275a_softc *sc = self; 414 415 sc->sc_enabled = on; 416 return (0); 417} 418 419 420/* ARGSUSED */ 421static void 422hpf1275a_wskbd_set_leds(void *self, int leds) 423{ 424 425 /* this keyboard has no leds; nothing to do */ 426 return; 427} 428 429 430static int 431hpf1275a_wskbd_ioctl(void *self, u_long cmd, void *data, int flag, 432 struct lwp *l) 433{ 434#ifdef WSDISPLAY_COMPAT_RAWKBD 435 struct hpf1275a_softc *sc = self; 436#endif 437 438 switch (cmd) { 439 case WSKBDIO_GTYPE: 440 *(int *)data = WSKBD_TYPE_HPC_KBD; /* may be use new type? */ 441 return (0); 442 443 case WSKBDIO_GETLEDS: 444 *(int *)data = 0; /* this keyboard has no leds */ 445 return (0); 446 447#ifdef WSDISPLAY_COMPAT_RAWKBD 448 case WSKBDIO_SETMODE: 449 sc->sc_rawkbd = (*(int *)data == WSKBD_RAW); 450 return (0); 451#endif 452 453 default: 454 return (EPASSTHROUGH); 455 } 456} 457