#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: hpf1275a_tty.c,v 1.34 2025/08/22 18:39:19 uwe Exp $");
#include "opt_wsdisplay_compat.h"
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/conf.h>
#include <sys/device.h>
#include <sys/tty.h>
#include <sys/fcntl.h>
#include <sys/proc.h>
#include <sys/systm.h>
#include <sys/kauth.h>
#include <dev/wscons/wsconsio.h>
#include <dev/wscons/wskbdvar.h>
#include <dev/wscons/wsksymdef.h>
#include <dev/wscons/wsksymvar.h>
#include <dev/pckbport/wskbdmap_mfii.h>
#ifdef WSDISPLAY_COMPAT_RAWKBD
#include <dev/hpc/pckbd_encode.h>
#endif
#include "ioconf.h"
struct hpf1275a_softc {
device_t sc_dev;
struct tty *sc_tp;
device_t sc_wskbd;
int sc_enabled;
#ifdef WSDISPLAY_COMPAT_RAWKBD
int sc_rawkbd;
#endif
};
extern void hpf1275aattach(int);
static int hpf1275a_open(dev_t, struct tty *);
static int hpf1275a_close(struct tty *, int);
static int hpf1275a_input(int, struct tty *);
static int hpf1275a_match(device_t, cfdata_t, void *);
static void hpf1275a_attach(device_t, device_t, void *);
static int hpf1275a_detach(device_t, int);
static int hpf1275a_wskbd_enable(void *, int);
static void hpf1275a_wskbd_set_leds(void *, int);
static int hpf1275a_wskbd_ioctl(void *, u_long, void *, int,
struct lwp *);
CFATTACH_DECL_NEW(hpf1275a, sizeof(struct hpf1275a_softc),
hpf1275a_match, hpf1275a_attach, hpf1275a_detach, NULL);
static struct linesw hpf1275a_disc = {
.l_name = "hpf1275a",
.l_open = hpf1275a_open,
.l_close = hpf1275a_close,
.l_read = ttyerrio,
.l_write = ttyerrio,
.l_ioctl = ttynullioctl,
.l_rint = hpf1275a_input,
.l_start = ttstart,
.l_modem = nullmodem,
.l_poll = ttpoll
};
static const struct wskbd_accessops hpf1275a_wskbd_accessops = {
hpf1275a_wskbd_enable,
hpf1275a_wskbd_set_leds,
hpf1275a_wskbd_ioctl
};
static const struct wskbd_mapdata hpf1275a_wskbd_keymapdata = {
pckbd_keydesctab, KB_US
};
static const uint8_t hpf1275a_to_xtscan[128] = {
[0x04] = 30,
[0x05] = 48,
[0x06] = 46,
[0x07] = 32,
[0x08] = 18,
[0x09] = 33,
[0x0a] = 34,
[0x0b] = 35,
[0x0c] = 23,
[0x0d] = 36,
[0x0e] = 37,
[0x0f] = 38,
[0x10] = 50,
[0x11] = 49,
[0x12] = 24,
[0x13] = 25,
[0x14] = 16,
[0x15] = 19,
[0x16] = 31,
[0x17] = 20,
[0x18] = 22,
[0x19] = 47,
[0x1a] = 17,
[0x1b] = 45,
[0x1c] = 21,
[0x1d] = 44,
[0x1e] = 2,
[0x1f] = 3,
[0x20] = 4,
[0x21] = 5,
[0x22] = 6,
[0x23] = 7,
[0x24] = 8,
[0x25] = 9,
[0x26] = 10,
[0x27] = 11,
[0x28] = 28,
[0x29] = 1,
[0x2a] = 14,
[0x2b] = 15,
[0x2c] = 57,
[0x2d] = 12,
[0x2e] = 13,
[0x2f] = 26,
[0x30] = 27,
[0x31] = 43,
[0x33] = 39,
[0x34] = 40,
[0x35] = 41,
[0x36] = 51,
[0x37] = 52,
[0x38] = 53,
[0x3a] = 59,
[0x3b] = 60,
[0x3c] = 61,
[0x3d] = 62,
[0x3e] = 63,
[0x3f] = 64,
[0x40] = 65,
[0x41] = 66,
[0x42] = 68,
[0x43] = 87,
[0x4c] = 211,
[0x4f] = 205,
[0x50] = 203,
[0x51] = 208,
[0x52] = 200,
[0x53] = 67,
[0x65] = 221,
[0x66] = 88,
[0x74] = 42,
[0x75] = 54,
[0x76] = 56,
[0x77] = 184,
[0x78] = 29,
};
void
hpf1275aattach(int n)
{
int error;
error = ttyldisc_attach(&hpf1275a_disc);
if (error) {
printf("%s: unable to register line discipline, error = %d\n",
hpf1275a_cd.cd_name, error);
return;
}
error = config_cfattach_attach(hpf1275a_cd.cd_name, &hpf1275a_ca);
if (error) {
printf("%s: unable to register cfattach, error = %d\n",
hpf1275a_cd.cd_name, error);
config_cfdriver_detach(&hpf1275a_cd);
(void) ttyldisc_detach(&hpf1275a_disc);
}
}
static int
hpf1275a_match(device_t self, cfdata_t cfdata, void *arg)
{
return (1);
}
static void
hpf1275a_attach(device_t parent, device_t self, void *aux)
{
struct hpf1275a_softc *sc = device_private(self);
struct wskbddev_attach_args wska;
wska.console = 0;
wska.keymap = &hpf1275a_wskbd_keymapdata;
wska.accessops = &hpf1275a_wskbd_accessops;
wska.accesscookie = sc;
sc->sc_dev = self;
sc->sc_enabled = 0;
#ifdef WSDISPLAY_COMPAT_RAWKBD
sc->sc_rawkbd = 0;
#endif
sc->sc_wskbd = config_found(self, &wska, wskbddevprint, CFARGS_NONE);
}
static int
hpf1275a_detach(device_t self, int flags)
{
int error;
error = config_detach_children(self, flags);
if (error)
return error;
return 0;
}
static int
hpf1275a_open(dev_t dev, struct tty *tp)
{
static struct cfdata hpf1275a_cfdata = {
.cf_name = "hpf1275a",
.cf_atname = "hpf1275a",
.cf_unit = 0,
.cf_fstate = FSTATE_STAR,
};
struct lwp *l = curlwp;
struct hpf1275a_softc *sc;
device_t self;
int error, s;
if ((error = kauth_authorize_device_tty(l->l_cred,
KAUTH_DEVICE_TTY_OPEN, tp)))
return (error);
s = spltty();
if (tp->t_linesw == &hpf1275a_disc) {
splx(s);
return 0;
}
self = config_attach_pseudo(&hpf1275a_cfdata);
if (self == NULL) {
splx(s);
return (EIO);
}
sc = device_private(self);
tp->t_sc = sc;
sc->sc_tp = tp;
splx(s);
return (0);
}
static int
hpf1275a_close(struct tty *tp, int flag)
{
struct hpf1275a_softc *sc = tp->t_sc;
int s;
s = spltty();
ttylock(tp);
ttyflush(tp, FREAD | FWRITE);
ttyunlock(tp);
ttyldisc_release(tp->t_linesw);
tp->t_linesw = ttyldisc_default();
if (sc != NULL) {
tp->t_sc = NULL;
if (sc->sc_tp == tp)
config_detach(sc->sc_dev, 0);
}
splx(s);
return (0);
}
static int
hpf1275a_input(int c, struct tty *tp)
{
struct hpf1275a_softc *sc = tp->t_sc;
int code;
u_int type;
int xtscan;
if (!sc->sc_enabled)
return (0);
if (c & TTY_ERRORMASK)
return (0);
code = c & TTY_CHARMASK;
if (code & 0x80) {
type = WSCONS_EVENT_KEY_UP;
code &= ~0x80;
} else
type = WSCONS_EVENT_KEY_DOWN;
xtscan = hpf1275a_to_xtscan[code];
if (xtscan == 0) {
aprint_error_dev(sc->sc_dev, "unknown code 0x%x\n", code);
return (0);
}
KASSERT(sc->sc_wskbd != NULL);
#ifdef WSDISPLAY_COMPAT_RAWKBD
if (sc->sc_rawkbd) {
u_char data[16];
int n;
n = pckbd_encode(type, xtscan, data);
wskbd_rawinput(sc->sc_wskbd, data, n);
} else
#endif
wskbd_input(sc->sc_wskbd, type, xtscan);
return (0);
}
static int
hpf1275a_wskbd_enable(void *self, int on)
{
struct hpf1275a_softc *sc = self;
sc->sc_enabled = on;
return (0);
}
static void
hpf1275a_wskbd_set_leds(void *self, int leds)
{
return;
}
static int
hpf1275a_wskbd_ioctl(void *self, u_long cmd, void *data, int flag,
struct lwp *l)
{
#ifdef WSDISPLAY_COMPAT_RAWKBD
struct hpf1275a_softc *sc = self;
#endif
switch (cmd) {
case WSKBDIO_GTYPE:
*(int *)data = WSKBD_TYPE_HPC_KBD;
return (0);
case WSKBDIO_GETLEDS:
*(int *)data = 0;
return (0);
#ifdef WSDISPLAY_COMPAT_RAWKBD
case WSKBDIO_SETMODE:
sc->sc_rawkbd = (*(int *)data == WSKBD_RAW);
return (0);
#endif
default:
return (EPASSTHROUGH);
}
}