hpf1275a_tty.c revision 1.26
11.26Schs/*	$NetBSD: hpf1275a_tty.c,v 1.26 2012/10/27 17:18:17 chs Exp $ */
21.1Suwe
31.1Suwe/*
41.1Suwe * Copyright (c) 2004 Valeriy E. Ushakov
51.1Suwe * All rights reserved.
61.1Suwe *
71.1Suwe * Redistribution and use in source and binary forms, with or without
81.1Suwe * modification, are permitted provided that the following conditions
91.1Suwe * are met:
101.1Suwe * 1. Redistributions of source code must retain the above copyright
111.1Suwe *    notice, this list of conditions and the following disclaimer.
121.1Suwe * 2. Redistributions in binary form must reproduce the above copyright
131.1Suwe *    notice, this list of conditions and the following disclaimer in the
141.1Suwe *    documentation and/or other materials provided with the distribution.
151.1Suwe * 3. The name of the author may not be used to endorse or promote products
161.1Suwe *    derived from this software without specific prior written permission
171.1Suwe *
181.1Suwe * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
191.1Suwe * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
201.1Suwe * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
211.1Suwe * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
221.1Suwe * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
231.1Suwe * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
241.1Suwe * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
251.1Suwe * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
261.1Suwe * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
271.1Suwe * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
281.1Suwe */
291.1Suwe
301.1Suwe#include <sys/cdefs.h>
311.26Schs__KERNEL_RCSID(0, "$NetBSD: hpf1275a_tty.c,v 1.26 2012/10/27 17:18:17 chs Exp $");
321.5Suwe
331.5Suwe#include "opt_wsdisplay_compat.h"
341.1Suwe
351.1Suwe#include <sys/param.h>
361.1Suwe#include <sys/kernel.h>
371.1Suwe#include <sys/conf.h>
381.1Suwe#include <sys/device.h>
391.1Suwe#include <sys/tty.h>
401.1Suwe#include <sys/fcntl.h>
411.13Suwe#include <sys/proc.h>
421.1Suwe#include <sys/systm.h>
431.9Syamt#include <sys/kauth.h>
441.1Suwe
451.13Suwe#include <dev/wscons/wsconsio.h>
461.13Suwe#include <dev/wscons/wskbdvar.h>
471.13Suwe#include <dev/wscons/wsksymdef.h>
481.10Suwe#include <dev/wscons/wsksymvar.h>
491.13Suwe
501.1Suwe#include <dev/pckbport/wskbdmap_mfii.h>
511.1Suwe#ifdef WSDISPLAY_COMPAT_RAWKBD
521.1Suwe#include <dev/hpc/pckbd_encode.h>
531.1Suwe#endif
541.1Suwe
551.1Suwe
561.1Suweextern struct cfdriver hpf1275a_cd;
571.1Suwe
581.1Suwestruct hpf1275a_softc {
591.26Schs	device_t sc_dev;
601.1Suwe
611.1Suwe	struct tty *sc_tp;		/* back reference to the tty */
621.25Scegger	device_t sc_wskbd;	/* wskbd child */
631.1Suwe	int sc_enabled;
641.5Suwe#ifdef WSDISPLAY_COMPAT_RAWKBD
651.5Suwe	int sc_rawkbd;
661.5Suwe#endif
671.1Suwe};
681.1Suwe
691.1Suwe
701.1Suwe/* pseudo-device initialization */
711.1Suweextern void	hpf1275aattach(int);
721.1Suwe
731.1Suwe/* line discipline methods */
741.1Suwestatic int	hpf1275a_open(dev_t, struct tty *);
751.1Suwestatic int	hpf1275a_close(struct tty *, int);
761.1Suwestatic int	hpf1275a_input(int, struct tty *);
771.1Suwe
781.1Suwe/* autoconf(9) methods */
791.25Sceggerstatic int	hpf1275a_match(device_t, cfdata_t, void *);
801.25Sceggerstatic void	hpf1275a_attach(device_t, device_t, void *);
811.25Sceggerstatic int	hpf1275a_detach(device_t, int);
821.1Suwe
831.1Suwe/* wskbd(4) accessops */
841.1Suwestatic int	hpf1275a_wskbd_enable(void *, int);
851.1Suwestatic void	hpf1275a_wskbd_set_leds(void *, int);
861.20Schristosstatic int	hpf1275a_wskbd_ioctl(void *, u_long, void *, int,
871.4Suwe				     struct lwp *);
881.1Suwe
891.1Suwe
901.13Suwe/*
911.13Suwe * It doesn't need to be exported, as only hpf1275aattach() uses it,
921.13Suwe * but there's no "official" way to make it static.
931.13Suwe */
941.26SchsCFATTACH_DECL_NEW(hpf1275a, sizeof(struct hpf1275a_softc),
951.1Suwe    hpf1275a_match, hpf1275a_attach, hpf1275a_detach, NULL);
961.1Suwe
971.1Suwe
981.1Suwestatic struct linesw hpf1275a_disc = {
991.3Sthorpej	.l_name = "hpf1275a",
1001.3Sthorpej	.l_open = hpf1275a_open,
1011.3Sthorpej	.l_close = hpf1275a_close,
1021.3Sthorpej	.l_read = ttyerrio,
1031.3Sthorpej	.l_write = ttyerrio,
1041.3Sthorpej	.l_ioctl = ttynullioctl,
1051.3Sthorpej	.l_rint = hpf1275a_input,
1061.3Sthorpej	.l_start = ttstart,
1071.3Sthorpej	.l_modem = nullmodem,
1081.3Sthorpej	.l_poll = ttpoll
1091.1Suwe};
1101.1Suwe
1111.1Suwe
1121.1Suwestatic const struct wskbd_accessops hpf1275a_wskbd_accessops = {
1131.1Suwe	hpf1275a_wskbd_enable,
1141.1Suwe	hpf1275a_wskbd_set_leds,
1151.1Suwe	hpf1275a_wskbd_ioctl
1161.1Suwe};
1171.1Suwe
1181.1Suwe
1191.11Suwestatic const struct wskbd_mapdata hpf1275a_wskbd_keymapdata = {
1201.1Suwe	pckbd_keydesctab, KB_US
1211.1Suwe};
1221.1Suwe
1231.1Suwe
1241.1Suwe/* F1275A scancodes -> XT scancodes so that we can use pckbd_keydesctab. */
1251.6Suwestatic const uint8_t hpf1275a_to_xtscan[128] = {
1261.1Suwe	[0x04] = 30,		/* a */
1271.1Suwe	[0x05] = 48,		/* b */
1281.1Suwe	[0x06] = 46,		/* c */
1291.1Suwe	[0x07] = 32,		/* d */
1301.1Suwe	[0x08] = 18,		/* e */
1311.1Suwe	[0x09] = 33,		/* f */
1321.1Suwe	[0x0a] = 34,		/* g */
1331.1Suwe	[0x0b] = 35,		/* h */
1341.1Suwe	[0x0c] = 23,		/* i */
1351.1Suwe	[0x0d] = 36,		/* j */
1361.1Suwe	[0x0e] = 37,		/* k */
1371.1Suwe	[0x0f] = 38,		/* l */
1381.1Suwe	[0x10] = 50,		/* m */
1391.1Suwe	[0x11] = 49,		/* n */
1401.1Suwe	[0x12] = 24,		/* o */
1411.1Suwe	[0x13] = 25,		/* p */
1421.1Suwe	[0x14] = 16,		/* q */
1431.1Suwe	[0x15] = 19,		/* r */
1441.1Suwe	[0x16] = 31,		/* s */
1451.1Suwe	[0x17] = 20,		/* t */
1461.1Suwe	[0x18] = 22,		/* u */
1471.1Suwe	[0x19] = 47,		/* v */
1481.1Suwe	[0x1a] = 17,		/* w */
1491.1Suwe	[0x1b] = 45,		/* x */
1501.1Suwe	[0x1c] = 21,		/* y */
1511.1Suwe	[0x1d] = 44,		/* z */
1521.1Suwe
1531.1Suwe	[0x1e] = 2,		/* 1 */
1541.1Suwe	[0x1f] = 3,		/* 2 */
1551.1Suwe	[0x20] = 4,		/* 3 */
1561.1Suwe	[0x21] = 5,		/* 4 */
1571.1Suwe	[0x22] = 6,		/* 5 */
1581.1Suwe	[0x23] = 7,		/* 6 */
1591.1Suwe	[0x24] = 8,		/* 7 */
1601.1Suwe	[0x25] = 9,		/* 8 */
1611.1Suwe	[0x26] = 10,		/* 9 */
1621.1Suwe	[0x27] = 11,		/* 0 */
1631.1Suwe
1641.1Suwe	[0x28] = 28,		/* Enter */
1651.1Suwe
1661.1Suwe	[0x29] = 1,		/* ESC */
1671.1Suwe	[0x2a] = 14,		/* Backspace */
1681.1Suwe	[0x2b] = 15,		/* Tab */
1691.1Suwe	[0x2c] = 57,		/* Space */
1701.1Suwe
1711.1Suwe	[0x2d] = 12,		/* - */
1721.1Suwe	[0x2e] = 13,		/* = */
1731.1Suwe	[0x2f] = 26,		/* [ */
1741.1Suwe	[0x30] = 27,		/* ] */
1751.1Suwe	[0x31] = 43,		/* \ */
1761.1Suwe
1771.1Suwe	[0x33] = 39,		/* ; */
1781.1Suwe	[0x34] = 40,		/* ' */
1791.1Suwe	[0x35] = 41,		/* ` */
1801.1Suwe	[0x36] = 51,		/* , */
1811.1Suwe	[0x37] = 52,		/* . */
1821.1Suwe	[0x38] = 53,		/* / */
1831.1Suwe
1841.1Suwe	[0x3a] = 59,		/* F1 */
1851.1Suwe	[0x3b] = 60,		/* F2 */
1861.1Suwe	[0x3c] = 61,		/* F3 */
1871.1Suwe	[0x3d] = 62,		/* F4 */
1881.1Suwe	[0x3e] = 63,		/* F5 */
1891.1Suwe	[0x3f] = 64,		/* F6 */
1901.1Suwe	[0x40] = 65,		/* F7 */
1911.1Suwe	[0x41] = 66,		/* F8 */
1921.1Suwe
1931.1Suwe	[0x42] = 68,		/* "OK" -> F10 */
1941.1Suwe	[0x43] = 87,		/* "Cancel" -> F11 */
1951.1Suwe
1961.1Suwe	[0x4c] = 211,		/* Del */
1971.1Suwe
1981.1Suwe	[0x4f] = 205,		/* Right */
1991.1Suwe	[0x50] = 203,		/* Left  */
2001.1Suwe	[0x51] = 208,		/* Down  */
2011.1Suwe	[0x52] = 200,		/* Up    */
2021.1Suwe
2031.1Suwe	[0x53] = 67,		/* "task switch" -> F9 */
2041.1Suwe
2051.1Suwe	[0x65] = 221,		/* windows */
2061.1Suwe	[0x66] = 88,		/* "keyboard" -> F12 */
2071.1Suwe
2081.1Suwe	[0x74] = 42,		/* Shift (left) */
2091.1Suwe	[0x75] = 54,		/* Shift (right) */
2101.1Suwe	[0x76] = 56,		/* Alt (left) */
2111.1Suwe	[0x77] = 184,		/* Fn -> AltGr == Mode Switch */
2121.1Suwe	[0x78] = 29,		/* Control (left) */
2131.1Suwe};
2141.1Suwe
2151.1Suwe
2161.1Suwe/*
2171.1Suwe * Pseudo-device initialization routine called from main().
2181.1Suwe */
2191.1Suwevoid
2201.19Schristoshpf1275aattach(int n)
2211.1Suwe{
2221.1Suwe	int error;
2231.1Suwe
2241.3Sthorpej	error = ttyldisc_attach(&hpf1275a_disc);
2251.3Sthorpej	if (error) {
2261.3Sthorpej		printf("%s: unable to register line discipline, error = %d\n",
2271.3Sthorpej		       hpf1275a_cd.cd_name, error);
2281.1Suwe		return;
2291.1Suwe	}
2301.1Suwe
2311.1Suwe	error = config_cfattach_attach(hpf1275a_cd.cd_name, &hpf1275a_ca);
2321.1Suwe	if (error) {
2331.1Suwe		printf("%s: unable to register cfattach, error = %d\n",
2341.1Suwe		       hpf1275a_cd.cd_name, error);
2351.1Suwe		config_cfdriver_detach(&hpf1275a_cd);
2361.4Suwe		(void) ttyldisc_detach(&hpf1275a_disc);
2371.1Suwe	}
2381.1Suwe}
2391.1Suwe
2401.1Suwe
2411.1Suwe/*
2421.1Suwe * Autoconf match routine.
2431.1Suwe *
2441.1Suwe * XXX: unused: config_attach_pseudo(9) does not call ca_match.
2451.1Suwe */
2461.1Suwestatic int
2471.26Schshpf1275a_match(device_t self, cfdata_t cfdata, void *arg)
2481.1Suwe{
2491.1Suwe
2501.1Suwe	/* pseudo-device; always present */
2511.1Suwe	return (1);
2521.1Suwe}
2531.1Suwe
2541.1Suwe
2551.1Suwe/*
2561.1Suwe * Autoconf attach routine.  Called by config_attach_pseudo(9) when we
2571.1Suwe * open the line discipline.
2581.1Suwe */
2591.1Suwestatic void
2601.26Schshpf1275a_attach(device_t parent, device_t self, void *aux)
2611.1Suwe{
2621.7Sthorpej	struct hpf1275a_softc *sc = device_private(self);
2631.1Suwe	struct wskbddev_attach_args wska;
2641.1Suwe
2651.1Suwe	wska.console = 0;
2661.1Suwe	wska.keymap = &hpf1275a_wskbd_keymapdata;
2671.1Suwe	wska.accessops = &hpf1275a_wskbd_accessops;
2681.1Suwe	wska.accesscookie = sc;
2691.1Suwe
2701.26Schs	sc->sc_dev = self;
2711.1Suwe	sc->sc_enabled = 0;
2721.5Suwe#ifdef WSDISPLAY_COMPAT_RAWKBD
2731.5Suwe	sc->sc_rawkbd = 0;
2741.5Suwe#endif
2751.1Suwe	sc->sc_wskbd = config_found(self, &wska, wskbddevprint);
2761.1Suwe}
2771.1Suwe
2781.1Suwe
2791.1Suwe/*
2801.1Suwe * Autoconf detach routine.  Called when we close the line discipline.
2811.1Suwe */
2821.1Suwestatic int
2831.25Sceggerhpf1275a_detach(device_t self, int flags)
2841.1Suwe{
2851.7Sthorpej	struct hpf1275a_softc *sc = device_private(self);
2861.1Suwe	int error;
2871.1Suwe
2881.1Suwe	if (sc->sc_wskbd == NULL)
2891.1Suwe		return (0);
2901.1Suwe
2911.1Suwe	error = config_detach(sc->sc_wskbd, 0);
2921.1Suwe
2931.1Suwe	return (error);
2941.1Suwe}
2951.1Suwe
2961.1Suwe
2971.1Suwe/*
2981.1Suwe * Line discipline open routine.
2991.1Suwe */
3001.12Suwestatic int
3011.19Schristoshpf1275a_open(dev_t dev, struct tty *tp)
3021.1Suwe{
3031.2Sthorpej	static struct cfdata hpf1275a_cfdata = {
3041.2Sthorpej		.cf_name = "hpf1275a",
3051.2Sthorpej		.cf_atname = "hpf1275a",
3061.21Sdrochner		.cf_unit = 0,
3071.2Sthorpej		.cf_fstate = FSTATE_STAR,
3081.2Sthorpej	};
3091.15Sad	struct lwp *l = curlwp;		/* XXX */
3101.1Suwe	struct hpf1275a_softc *sc;
3111.26Schs	device_t self;
3121.1Suwe	int error, s;
3131.1Suwe
3141.16Selad	if ((error = kauth_authorize_device_tty(l->l_cred,
3151.16Selad			KAUTH_DEVICE_TTY_OPEN, tp)))
3161.15Sad		return (error);
3171.1Suwe
3181.1Suwe	s = spltty();
3191.1Suwe
3201.14Suwe	if (tp->t_linesw == &hpf1275a_disc) {
3211.14Suwe		splx(s);
3221.14Suwe		return 0;
3231.14Suwe	}
3241.14Suwe
3251.26Schs	self = config_attach_pseudo(&hpf1275a_cfdata);
3261.26Schs	if (self == NULL) {
3271.1Suwe		splx(s);
3281.1Suwe		return (EIO);
3291.1Suwe	}
3301.1Suwe
3311.26Schs	tp->t_sc = device_private(self);
3321.1Suwe	sc->sc_tp = tp;
3331.1Suwe
3341.1Suwe	splx(s);
3351.1Suwe	return (0);
3361.1Suwe}
3371.1Suwe
3381.1Suwe
3391.1Suwe/*
3401.1Suwe * Line discipline close routine.
3411.1Suwe */
3421.12Suwestatic int
3431.19Schristoshpf1275a_close(struct tty *tp, int flag)
3441.1Suwe{
3451.13Suwe	struct hpf1275a_softc *sc = tp->t_sc;
3461.1Suwe	int s;
3471.1Suwe
3481.1Suwe	s = spltty();
3491.22Sad	mutex_spin_enter(&tty_lock);
3501.1Suwe	ttyflush(tp, FREAD | FWRITE);
3511.22Sad	mutex_spin_exit(&tty_lock);	 /* XXX */
3521.3Sthorpej	ttyldisc_release(tp->t_linesw);
3531.3Sthorpej	tp->t_linesw = ttyldisc_default();
3541.1Suwe	if (sc != NULL) {
3551.1Suwe		tp->t_sc = NULL;
3561.1Suwe		if (sc->sc_tp == tp)
3571.26Schs			config_detach(sc->sc_dev, 0);
3581.1Suwe	}
3591.1Suwe	splx(s);
3601.1Suwe	return (0);
3611.1Suwe}
3621.1Suwe
3631.1Suwe
3641.1Suwe/*
3651.1Suwe * Feed input from the keyboard to wskbd(4).
3661.1Suwe */
3671.12Suwestatic int
3681.1Suwehpf1275a_input(int c, struct tty *tp)
3691.1Suwe{
3701.13Suwe	struct hpf1275a_softc *sc = tp->t_sc;
3711.1Suwe	int code;
3721.1Suwe	u_int type;
3731.1Suwe	int xtscan;
3741.1Suwe
3751.1Suwe	if (!sc->sc_enabled)
3761.1Suwe		return (0);
3771.1Suwe
3781.1Suwe	if (c & TTY_ERRORMASK)
3791.1Suwe		return (0);	/* TODO? */
3801.1Suwe
3811.1Suwe	code = c & TTY_CHARMASK;
3821.1Suwe	if (code & 0x80) {
3831.1Suwe		type = WSCONS_EVENT_KEY_UP;
3841.1Suwe		code &= ~0x80;
3851.1Suwe	} else
3861.1Suwe		type = WSCONS_EVENT_KEY_DOWN;
3871.1Suwe
3881.1Suwe	xtscan = hpf1275a_to_xtscan[code];
3891.1Suwe	if (xtscan == 0) {
3901.26Schs		aprint_error_dev(sc->sc_dev, "unknown code 0x%x\n", code);
3911.1Suwe		return (0);
3921.1Suwe	}
3931.1Suwe
3941.1Suwe	KASSERT(sc->sc_wskbd != NULL);
3951.5Suwe
3961.5Suwe#ifdef WSDISPLAY_COMPAT_RAWKBD
3971.5Suwe	if (sc->sc_rawkbd) {
3981.5Suwe		u_char data[16];
3991.5Suwe		int n;
4001.5Suwe
4011.5Suwe		n = pckbd_encode(type, xtscan, data);
4021.5Suwe		wskbd_rawinput(sc->sc_wskbd, data, n);
4031.5Suwe	} else
4041.5Suwe#endif
4051.5Suwe		wskbd_input(sc->sc_wskbd, type, xtscan);
4061.1Suwe
4071.1Suwe	return (0);
4081.1Suwe}
4091.1Suwe
4101.1Suwe
4111.1Suwestatic int
4121.1Suwehpf1275a_wskbd_enable(void *self, int on)
4131.1Suwe{
4141.7Sthorpej	struct hpf1275a_softc *sc = self;
4151.1Suwe
4161.1Suwe	sc->sc_enabled = on;
4171.1Suwe	return (0);
4181.1Suwe}
4191.1Suwe
4201.1Suwe
4211.1Suwe/* ARGSUSED */
4221.1Suwestatic void
4231.19Schristoshpf1275a_wskbd_set_leds(void *self, int leds)
4241.1Suwe{
4251.1Suwe
4261.1Suwe	/* this keyboard has no leds; nothing to do */
4271.1Suwe	return;
4281.1Suwe}
4291.1Suwe
4301.1Suwe
4311.1Suwestatic int
4321.20Schristoshpf1275a_wskbd_ioctl(void *self, u_long cmd, void *data, int flag,
4331.19Schristos		     struct lwp *l)
4341.1Suwe{
4351.5Suwe#ifdef WSDISPLAY_COMPAT_RAWKBD
4361.7Sthorpej	struct hpf1275a_softc *sc = self;
4371.5Suwe#endif
4381.1Suwe
4391.1Suwe	switch (cmd) {
4401.1Suwe	case WSKBDIO_GTYPE:
4411.1Suwe		*(int *)data = WSKBD_TYPE_HPC_KBD; /* may be use new type? */
4421.1Suwe		return (0);
4431.1Suwe
4441.1Suwe	case WSKBDIO_GETLEDS:
4451.1Suwe		*(int *)data = 0; /* this keyboard has no leds */
4461.1Suwe		return (0);
4471.1Suwe
4481.5Suwe#ifdef WSDISPLAY_COMPAT_RAWKBD
4491.5Suwe	case WSKBDIO_SETMODE:
4501.5Suwe		sc->sc_rawkbd = (*(int *)data == WSKBD_RAW);
4511.5Suwe		return (0);
4521.5Suwe#endif
4531.5Suwe
4541.1Suwe	default:
4551.1Suwe		return (EPASSTHROUGH);
4561.1Suwe	}
4571.1Suwe}
458