Home | History | Annotate | Line # | Download | only in hpc
      1 /*	$NetBSD: hpf1275a_tty.c,v 1.34 2025/08/22 18:39:19 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.34 2025/08/22 18:39:19 uwe 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 
     57 struct 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 */
     70 extern void	hpf1275aattach(int);
     71 
     72 /* line discipline methods */
     73 static int	hpf1275a_open(dev_t, struct tty *);
     74 static int	hpf1275a_close(struct tty *, int);
     75 static int	hpf1275a_input(int, struct tty *);
     76 
     77 /* autoconf(9) methods */
     78 static int	hpf1275a_match(device_t, cfdata_t, void *);
     79 static void	hpf1275a_attach(device_t, device_t, void *);
     80 static int	hpf1275a_detach(device_t, int);
     81 
     82 /* wskbd(4) accessops */
     83 static int	hpf1275a_wskbd_enable(void *, int);
     84 static void	hpf1275a_wskbd_set_leds(void *, int);
     85 static 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  */
     93 CFATTACH_DECL_NEW(hpf1275a, sizeof(struct hpf1275a_softc),
     94     hpf1275a_match, hpf1275a_attach, hpf1275a_detach, NULL);
     95 
     96 
     97 static 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 
    111 static const struct wskbd_accessops hpf1275a_wskbd_accessops = {
    112 	hpf1275a_wskbd_enable,
    113 	hpf1275a_wskbd_set_leds,
    114 	hpf1275a_wskbd_ioctl
    115 };
    116 
    117 
    118 static 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. */
    124 static 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  */
    218 void
    219 hpf1275aattach(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  */
    245 static int
    246 hpf1275a_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  */
    258 static void
    259 hpf1275a_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  */
    281 static int
    282 hpf1275a_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  */
    298 static int
    299 hpf1275a_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  */
    341 static int
    342 hpf1275a_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  */
    366 static int
    367 hpf1275a_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 
    410 static int
    411 hpf1275a_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 */
    421 static void
    422 hpf1275a_wskbd_set_leds(void *self, int leds)
    423 {
    424 
    425 	/* this keyboard has no leds; nothing to do */
    426 	return;
    427 }
    428 
    429 
    430 static int
    431 hpf1275a_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