hpf1275a_tty.c revision 1.15
11.15Sad/* $NetBSD: hpf1275a_tty.c,v 1.15 2006/07/21 16:48:48 ad 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.15Sad__KERNEL_RCSID(0, "$NetBSD: hpf1275a_tty.c,v 1.15 2006/07/21 16:48:48 ad 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#ifdef GPROF 451.1Suwe#include <sys/gmon.h> 461.1Suwe#endif 471.1Suwe 481.13Suwe#include <dev/wscons/wsconsio.h> 491.13Suwe#include <dev/wscons/wskbdvar.h> 501.13Suwe#include <dev/wscons/wsksymdef.h> 511.10Suwe#include <dev/wscons/wsksymvar.h> 521.13Suwe 531.1Suwe#include <dev/pckbport/wskbdmap_mfii.h> 541.1Suwe#ifdef WSDISPLAY_COMPAT_RAWKBD 551.1Suwe#include <dev/hpc/pckbd_encode.h> 561.1Suwe#endif 571.1Suwe 581.1Suwe 591.1Suweextern struct cfdriver hpf1275a_cd; 601.1Suwe 611.1Suwestruct hpf1275a_softc { 621.1Suwe struct device sc_dev; 631.1Suwe 641.1Suwe struct tty *sc_tp; /* back reference to the tty */ 651.1Suwe struct device *sc_wskbd; /* wskbd child */ 661.1Suwe int sc_enabled; 671.5Suwe#ifdef WSDISPLAY_COMPAT_RAWKBD 681.5Suwe int sc_rawkbd; 691.5Suwe#endif 701.1Suwe}; 711.1Suwe 721.1Suwe 731.1Suwe/* pseudo-device initialization */ 741.1Suweextern void hpf1275aattach(int); 751.1Suwe 761.1Suwe/* line discipline methods */ 771.1Suwestatic int hpf1275a_open(dev_t, struct tty *); 781.1Suwestatic int hpf1275a_close(struct tty *, int); 791.1Suwestatic int hpf1275a_input(int, struct tty *); 801.1Suwe 811.1Suwe/* autoconf(9) methods */ 821.1Suwestatic int hpf1275a_match(struct device *, struct cfdata *, void *); 831.1Suwestatic void hpf1275a_attach(struct device *, struct device *, void *); 841.1Suwestatic int hpf1275a_detach(struct device *, int); 851.1Suwe 861.1Suwe/* wskbd(4) accessops */ 871.1Suwestatic int hpf1275a_wskbd_enable(void *, int); 881.1Suwestatic void hpf1275a_wskbd_set_leds(void *, int); 891.1Suwestatic int hpf1275a_wskbd_ioctl(void *, u_long, caddr_t, int, 901.4Suwe struct lwp *); 911.1Suwe 921.1Suwe 931.13Suwe/* 941.13Suwe * It doesn't need to be exported, as only hpf1275aattach() uses it, 951.13Suwe * but there's no "official" way to make it static. 961.13Suwe */ 971.1SuweCFATTACH_DECL(hpf1275a, sizeof(struct hpf1275a_softc), 981.1Suwe hpf1275a_match, hpf1275a_attach, hpf1275a_detach, NULL); 991.1Suwe 1001.1Suwe 1011.1Suwestatic struct linesw hpf1275a_disc = { 1021.3Sthorpej .l_name = "hpf1275a", 1031.3Sthorpej .l_open = hpf1275a_open, 1041.3Sthorpej .l_close = hpf1275a_close, 1051.3Sthorpej .l_read = ttyerrio, 1061.3Sthorpej .l_write = ttyerrio, 1071.3Sthorpej .l_ioctl = ttynullioctl, 1081.3Sthorpej .l_rint = hpf1275a_input, 1091.3Sthorpej .l_start = ttstart, 1101.3Sthorpej .l_modem = nullmodem, 1111.3Sthorpej .l_poll = ttpoll 1121.1Suwe}; 1131.1Suwe 1141.1Suwe 1151.1Suwestatic const struct wskbd_accessops hpf1275a_wskbd_accessops = { 1161.1Suwe hpf1275a_wskbd_enable, 1171.1Suwe hpf1275a_wskbd_set_leds, 1181.1Suwe hpf1275a_wskbd_ioctl 1191.1Suwe}; 1201.1Suwe 1211.1Suwe 1221.11Suwestatic const struct wskbd_mapdata hpf1275a_wskbd_keymapdata = { 1231.1Suwe pckbd_keydesctab, KB_US 1241.1Suwe}; 1251.1Suwe 1261.1Suwe 1271.1Suwe/* F1275A scancodes -> XT scancodes so that we can use pckbd_keydesctab. */ 1281.6Suwestatic const uint8_t hpf1275a_to_xtscan[128] = { 1291.1Suwe [0x04] = 30, /* a */ 1301.1Suwe [0x05] = 48, /* b */ 1311.1Suwe [0x06] = 46, /* c */ 1321.1Suwe [0x07] = 32, /* d */ 1331.1Suwe [0x08] = 18, /* e */ 1341.1Suwe [0x09] = 33, /* f */ 1351.1Suwe [0x0a] = 34, /* g */ 1361.1Suwe [0x0b] = 35, /* h */ 1371.1Suwe [0x0c] = 23, /* i */ 1381.1Suwe [0x0d] = 36, /* j */ 1391.1Suwe [0x0e] = 37, /* k */ 1401.1Suwe [0x0f] = 38, /* l */ 1411.1Suwe [0x10] = 50, /* m */ 1421.1Suwe [0x11] = 49, /* n */ 1431.1Suwe [0x12] = 24, /* o */ 1441.1Suwe [0x13] = 25, /* p */ 1451.1Suwe [0x14] = 16, /* q */ 1461.1Suwe [0x15] = 19, /* r */ 1471.1Suwe [0x16] = 31, /* s */ 1481.1Suwe [0x17] = 20, /* t */ 1491.1Suwe [0x18] = 22, /* u */ 1501.1Suwe [0x19] = 47, /* v */ 1511.1Suwe [0x1a] = 17, /* w */ 1521.1Suwe [0x1b] = 45, /* x */ 1531.1Suwe [0x1c] = 21, /* y */ 1541.1Suwe [0x1d] = 44, /* z */ 1551.1Suwe 1561.1Suwe [0x1e] = 2, /* 1 */ 1571.1Suwe [0x1f] = 3, /* 2 */ 1581.1Suwe [0x20] = 4, /* 3 */ 1591.1Suwe [0x21] = 5, /* 4 */ 1601.1Suwe [0x22] = 6, /* 5 */ 1611.1Suwe [0x23] = 7, /* 6 */ 1621.1Suwe [0x24] = 8, /* 7 */ 1631.1Suwe [0x25] = 9, /* 8 */ 1641.1Suwe [0x26] = 10, /* 9 */ 1651.1Suwe [0x27] = 11, /* 0 */ 1661.1Suwe 1671.1Suwe [0x28] = 28, /* Enter */ 1681.1Suwe 1691.1Suwe [0x29] = 1, /* ESC */ 1701.1Suwe [0x2a] = 14, /* Backspace */ 1711.1Suwe [0x2b] = 15, /* Tab */ 1721.1Suwe [0x2c] = 57, /* Space */ 1731.1Suwe 1741.1Suwe [0x2d] = 12, /* - */ 1751.1Suwe [0x2e] = 13, /* = */ 1761.1Suwe [0x2f] = 26, /* [ */ 1771.1Suwe [0x30] = 27, /* ] */ 1781.1Suwe [0x31] = 43, /* \ */ 1791.1Suwe 1801.1Suwe [0x33] = 39, /* ; */ 1811.1Suwe [0x34] = 40, /* ' */ 1821.1Suwe [0x35] = 41, /* ` */ 1831.1Suwe [0x36] = 51, /* , */ 1841.1Suwe [0x37] = 52, /* . */ 1851.1Suwe [0x38] = 53, /* / */ 1861.1Suwe 1871.1Suwe [0x3a] = 59, /* F1 */ 1881.1Suwe [0x3b] = 60, /* F2 */ 1891.1Suwe [0x3c] = 61, /* F3 */ 1901.1Suwe [0x3d] = 62, /* F4 */ 1911.1Suwe [0x3e] = 63, /* F5 */ 1921.1Suwe [0x3f] = 64, /* F6 */ 1931.1Suwe [0x40] = 65, /* F7 */ 1941.1Suwe [0x41] = 66, /* F8 */ 1951.1Suwe 1961.1Suwe [0x42] = 68, /* "OK" -> F10 */ 1971.1Suwe [0x43] = 87, /* "Cancel" -> F11 */ 1981.1Suwe 1991.1Suwe [0x4c] = 211, /* Del */ 2001.1Suwe 2011.1Suwe [0x4f] = 205, /* Right */ 2021.1Suwe [0x50] = 203, /* Left */ 2031.1Suwe [0x51] = 208, /* Down */ 2041.1Suwe [0x52] = 200, /* Up */ 2051.1Suwe 2061.1Suwe [0x53] = 67, /* "task switch" -> F9 */ 2071.1Suwe 2081.1Suwe [0x65] = 221, /* windows */ 2091.1Suwe [0x66] = 88, /* "keyboard" -> F12 */ 2101.1Suwe 2111.1Suwe [0x74] = 42, /* Shift (left) */ 2121.1Suwe [0x75] = 54, /* Shift (right) */ 2131.1Suwe [0x76] = 56, /* Alt (left) */ 2141.1Suwe [0x77] = 184, /* Fn -> AltGr == Mode Switch */ 2151.1Suwe [0x78] = 29, /* Control (left) */ 2161.1Suwe}; 2171.1Suwe 2181.1Suwe 2191.1Suwe/* 2201.1Suwe * Pseudo-device initialization routine called from main(). 2211.1Suwe */ 2221.1Suwevoid 2231.1Suwehpf1275aattach(int n) 2241.1Suwe{ 2251.1Suwe int error; 2261.1Suwe 2271.3Sthorpej error = ttyldisc_attach(&hpf1275a_disc); 2281.3Sthorpej if (error) { 2291.3Sthorpej printf("%s: unable to register line discipline, error = %d\n", 2301.3Sthorpej hpf1275a_cd.cd_name, error); 2311.1Suwe return; 2321.1Suwe } 2331.1Suwe 2341.1Suwe error = config_cfattach_attach(hpf1275a_cd.cd_name, &hpf1275a_ca); 2351.1Suwe if (error) { 2361.1Suwe printf("%s: unable to register cfattach, error = %d\n", 2371.1Suwe hpf1275a_cd.cd_name, error); 2381.1Suwe config_cfdriver_detach(&hpf1275a_cd); 2391.4Suwe (void) ttyldisc_detach(&hpf1275a_disc); 2401.1Suwe } 2411.1Suwe} 2421.1Suwe 2431.1Suwe 2441.1Suwe/* 2451.1Suwe * Autoconf match routine. 2461.1Suwe * 2471.1Suwe * XXX: unused: config_attach_pseudo(9) does not call ca_match. 2481.1Suwe */ 2491.1Suwestatic int 2501.1Suwehpf1275a_match(struct device *self, struct cfdata *cfdata, void *arg) 2511.1Suwe{ 2521.1Suwe 2531.1Suwe /* pseudo-device; always present */ 2541.1Suwe return (1); 2551.1Suwe} 2561.1Suwe 2571.1Suwe 2581.1Suwe/* 2591.1Suwe * Autoconf attach routine. Called by config_attach_pseudo(9) when we 2601.1Suwe * open the line discipline. 2611.1Suwe */ 2621.1Suwestatic void 2631.1Suwehpf1275a_attach(struct device *parent, struct device *self, void *aux) 2641.1Suwe{ 2651.7Sthorpej struct hpf1275a_softc *sc = device_private(self); 2661.1Suwe struct wskbddev_attach_args wska; 2671.1Suwe 2681.1Suwe wska.console = 0; 2691.1Suwe wska.keymap = &hpf1275a_wskbd_keymapdata; 2701.1Suwe wska.accessops = &hpf1275a_wskbd_accessops; 2711.1Suwe wska.accesscookie = sc; 2721.1Suwe 2731.1Suwe sc->sc_enabled = 0; 2741.5Suwe#ifdef WSDISPLAY_COMPAT_RAWKBD 2751.5Suwe sc->sc_rawkbd = 0; 2761.5Suwe#endif 2771.1Suwe sc->sc_wskbd = config_found(self, &wska, wskbddevprint); 2781.1Suwe} 2791.1Suwe 2801.1Suwe 2811.1Suwe/* 2821.1Suwe * Autoconf detach routine. Called when we close the line discipline. 2831.1Suwe */ 2841.1Suwestatic int 2851.1Suwehpf1275a_detach(struct device *self, int flags) 2861.1Suwe{ 2871.7Sthorpej struct hpf1275a_softc *sc = device_private(self); 2881.1Suwe int error; 2891.1Suwe 2901.1Suwe if (sc->sc_wskbd == NULL) 2911.1Suwe return (0); 2921.1Suwe 2931.1Suwe error = config_detach(sc->sc_wskbd, 0); 2941.1Suwe 2951.1Suwe return (error); 2961.1Suwe} 2971.1Suwe 2981.1Suwe 2991.1Suwe/* 3001.1Suwe * Line discipline open routine. 3011.1Suwe */ 3021.12Suwestatic int 3031.1Suwehpf1275a_open(dev_t dev, struct tty *tp) 3041.1Suwe{ 3051.2Sthorpej static struct cfdata hpf1275a_cfdata = { 3061.2Sthorpej .cf_name = "hpf1275a", 3071.2Sthorpej .cf_atname = "hpf1275a", 3081.2Sthorpej .cf_unit = DVUNIT_ANY, 3091.2Sthorpej .cf_fstate = FSTATE_STAR, 3101.2Sthorpej }; 3111.15Sad struct lwp *l = curlwp; /* XXX */ 3121.1Suwe struct hpf1275a_softc *sc; 3131.1Suwe int error, s; 3141.1Suwe 3151.15Sad error = kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER, 3161.15Sad &l->l_acflag); 3171.13Suwe if (error != 0) 3181.15Sad return (error); 3191.1Suwe 3201.1Suwe s = spltty(); 3211.1Suwe 3221.14Suwe if (tp->t_linesw == &hpf1275a_disc) { 3231.14Suwe splx(s); 3241.14Suwe return 0; 3251.14Suwe } 3261.14Suwe 3271.13Suwe sc = (struct hpf1275a_softc *)config_attach_pseudo(&hpf1275a_cfdata); 3281.1Suwe if (sc == NULL) { 3291.1Suwe splx(s); 3301.1Suwe return (EIO); 3311.1Suwe } 3321.1Suwe 3331.1Suwe tp->t_sc = sc; 3341.1Suwe sc->sc_tp = tp; 3351.1Suwe 3361.1Suwe splx(s); 3371.1Suwe return (0); 3381.1Suwe} 3391.1Suwe 3401.1Suwe 3411.1Suwe/* 3421.1Suwe * Line discipline close routine. 3431.1Suwe */ 3441.12Suwestatic int 3451.1Suwehpf1275a_close(struct tty *tp, int flag) 3461.1Suwe{ 3471.13Suwe struct hpf1275a_softc *sc = tp->t_sc; 3481.1Suwe int s; 3491.1Suwe 3501.1Suwe s = spltty(); 3511.1Suwe ttyflush(tp, FREAD | FWRITE); 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.1Suwe 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.6Suwe printf("%s: unknown code 0x%x\n", sc->sc_dev.dv_xname, 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.1Suwehpf1275a_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.1Suwehpf1275a_wskbd_ioctl(void *self, u_long cmd, caddr_t data, int flag, 4331.4Suwe 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