1*c7fb772bSthorpej /* $NetBSD: dtkbd.c,v 1.13 2021/08/07 16:19:02 thorpej Exp $ */
29aa9b8ebSad
39aa9b8ebSad /*-
49aa9b8ebSad * Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
59aa9b8ebSad * All rights reserved.
69aa9b8ebSad *
79aa9b8ebSad * This code is derived from software contributed to The NetBSD Foundation
89aa9b8ebSad * by Andrew Doran.
99aa9b8ebSad *
109aa9b8ebSad * Redistribution and use in source and binary forms, with or without
119aa9b8ebSad * modification, are permitted provided that the following conditions
129aa9b8ebSad * are met:
139aa9b8ebSad * 1. Redistributions of source code must retain the above copyright
149aa9b8ebSad * notice, this list of conditions and the following disclaimer.
159aa9b8ebSad * 2. Redistributions in binary form must reproduce the above copyright
169aa9b8ebSad * notice, this list of conditions and the following disclaimer in the
179aa9b8ebSad * documentation and/or other materials provided with the distribution.
189aa9b8ebSad *
199aa9b8ebSad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
209aa9b8ebSad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
219aa9b8ebSad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
229aa9b8ebSad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
239aa9b8ebSad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
249aa9b8ebSad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
259aa9b8ebSad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
269aa9b8ebSad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
279aa9b8ebSad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
289aa9b8ebSad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
299aa9b8ebSad * POSSIBILITY OF SUCH DAMAGE.
309aa9b8ebSad */
319aa9b8ebSad
329aa9b8ebSad #include <sys/cdefs.h>
33*c7fb772bSthorpej __KERNEL_RCSID(0, "$NetBSD: dtkbd.c,v 1.13 2021/08/07 16:19:02 thorpej Exp $");
349aa9b8ebSad
359aa9b8ebSad #include "locators.h"
369aa9b8ebSad
379aa9b8ebSad #include <sys/param.h>
38a0640b2bSmatt #include <sys/bus.h>
39a0640b2bSmatt #include <sys/callout.h>
409aa9b8ebSad #include <sys/device.h>
419aa9b8ebSad #include <sys/ioctl.h>
42a0640b2bSmatt #include <sys/systm.h>
439aa9b8ebSad
449aa9b8ebSad #include <dev/wscons/wsconsio.h>
459aa9b8ebSad #include <dev/wscons/wskbdvar.h>
469aa9b8ebSad #include <dev/wscons/wsksymdef.h>
479aa9b8ebSad #include <dev/wscons/wsksymvar.h>
489aa9b8ebSad #include <dev/dec/wskbdmap_lk201.h>
499aa9b8ebSad #include <dev/tc/tcvar.h>
509aa9b8ebSad
519aa9b8ebSad #include <pmax/tc/dtreg.h>
529aa9b8ebSad #include <pmax/tc/dtvar.h>
539aa9b8ebSad
549aa9b8ebSad #include <pmax/pmax/cons.h>
559aa9b8ebSad
569aa9b8ebSad struct dtkbd_softc {
5703335d0bStsutsui device_t sc_dev;
5803335d0bStsutsui device_t sc_wskbddev;
599aa9b8ebSad int sc_enabled;
609aa9b8ebSad };
619aa9b8ebSad
6203335d0bStsutsui int dtkbd_match(device_t, cfdata_t, void *);
6303335d0bStsutsui void dtkbd_attach(device_t, device_t, void *);
649aa9b8ebSad int dtkbd_enable(void *, int);
6553524e44Schristos int dtkbd_ioctl(void *, u_long, void *, int, struct lwp *);
669aa9b8ebSad void dtkbd_cngetc(void *, u_int *, int *);
679aa9b8ebSad void dtkbd_cnpollc(void *, int);
689aa9b8ebSad int dtkbd_process_msg(struct dt_msg *, u_int *, int *);
69520489e1Sad void dtkbd_handler(void *, struct dt_msg *);
709aa9b8ebSad void dtkbd_set_leds(void *, int);
719aa9b8ebSad
729aa9b8ebSad const struct wskbd_accessops dtkbd_accessops = {
739aa9b8ebSad dtkbd_enable,
749aa9b8ebSad dtkbd_set_leds,
759aa9b8ebSad dtkbd_ioctl,
769aa9b8ebSad };
779aa9b8ebSad
789aa9b8ebSad const struct wskbd_consops dtkbd_consops = {
799aa9b8ebSad dtkbd_cngetc,
809aa9b8ebSad dtkbd_cnpollc,
819aa9b8ebSad };
829aa9b8ebSad
8303335d0bStsutsui CFATTACH_DECL_NEW(dtkbd, sizeof(struct dtkbd_softc),
849aa9b8ebSad dtkbd_match, dtkbd_attach, NULL, NULL);
859aa9b8ebSad
869aa9b8ebSad const struct wskbd_mapdata dtkbd_keymapdata = {
879aa9b8ebSad lkkbd_keydesctab,
889aa9b8ebSad #ifdef DTKBD_LAYOUT
899aa9b8ebSad DTKBD_LAYOUT,
909aa9b8ebSad #else
919aa9b8ebSad KB_US | KB_LK401,
929aa9b8ebSad #endif
939aa9b8ebSad };
949aa9b8ebSad
959aa9b8ebSad int dtkbd_isconsole;
96d6b26ac1Smhitch uint8_t dtkbd_map[10];
979aa9b8ebSad int dtkbd_maplen;
989aa9b8ebSad
999aa9b8ebSad int
dtkbd_match(device_t parent,cfdata_t cf,void * aux)10003335d0bStsutsui dtkbd_match(device_t parent, cfdata_t cf, void *aux)
1019aa9b8ebSad {
1029aa9b8ebSad struct dt_attach_args *dta;
1039aa9b8ebSad
1049aa9b8ebSad dta = aux;
1059aa9b8ebSad return (dta->dta_addr == DT_ADDR_KBD);
1069aa9b8ebSad }
1079aa9b8ebSad
1089aa9b8ebSad void
dtkbd_attach(device_t parent,device_t self,void * aux)10903335d0bStsutsui dtkbd_attach(device_t parent, device_t self, void *aux)
1109aa9b8ebSad {
1119aa9b8ebSad struct dt_softc *dt;
1129aa9b8ebSad struct dtkbd_softc *sc;
1139aa9b8ebSad struct wskbddev_attach_args a;
1149aa9b8ebSad
11503335d0bStsutsui dt = device_private(parent);
11603335d0bStsutsui sc = device_private(self);
11703335d0bStsutsui sc->sc_dev = self;
1189aa9b8ebSad
1199aa9b8ebSad printf("\n");
1209aa9b8ebSad
12103335d0bStsutsui if (dt_establish_handler(dt, &dt_kbd_dv, sc, dtkbd_handler)) {
12203335d0bStsutsui printf("%s: unable to establish handler\n", device_xname(self));
1239aa9b8ebSad return;
1249aa9b8ebSad }
1259aa9b8ebSad
1269aa9b8ebSad sc->sc_enabled = 1;
1279aa9b8ebSad
1289aa9b8ebSad a.console = dtkbd_isconsole;
1299aa9b8ebSad a.keymap = &dtkbd_keymapdata;
1309aa9b8ebSad a.accessops = &dtkbd_accessops;
1319aa9b8ebSad a.accesscookie = sc;
132*c7fb772bSthorpej sc->sc_wskbddev = config_found(self, &a, wskbddevprint, CFARGS_NONE);
1339aa9b8ebSad }
1349aa9b8ebSad
1359aa9b8ebSad void
dtkbd_cnattach(void)1369aa9b8ebSad dtkbd_cnattach(void)
1379aa9b8ebSad {
1389aa9b8ebSad
1399aa9b8ebSad dtkbd_isconsole = 1;
1409aa9b8ebSad dt_cninit();
1419aa9b8ebSad
1429aa9b8ebSad wskbd_cnattach(&dtkbd_consops, &dtkbd_map, &dtkbd_keymapdata);
1439aa9b8ebSad }
1449aa9b8ebSad
1459aa9b8ebSad int
dtkbd_enable(void * v,int on)1469aa9b8ebSad dtkbd_enable(void *v, int on)
1479aa9b8ebSad {
1489aa9b8ebSad struct dtkbd_softc *sc;
1499aa9b8ebSad
1509aa9b8ebSad sc = v;
1519aa9b8ebSad sc->sc_enabled = on;
1529aa9b8ebSad
1539aa9b8ebSad return (0);
1549aa9b8ebSad }
1559aa9b8ebSad
1569aa9b8ebSad void
dtkbd_cngetc(void * v,u_int * type,int * data)1579aa9b8ebSad dtkbd_cngetc(void *v, u_int *type, int *data)
1589aa9b8ebSad {
1599aa9b8ebSad struct dt_msg msg;
1609aa9b8ebSad static u_int types[20];
1619aa9b8ebSad static int cnt, i, vals[20];
1629aa9b8ebSad
163520489e1Sad while (i >= cnt) {
1649aa9b8ebSad for (;;) {
1659aa9b8ebSad if (dt_msg_get(&msg, 0) == DT_GET_DONE)
166520489e1Sad if (msg.src == dt_kbd_addr &&
167520489e1Sad !DT_CTL_P(msg.ctl))
1689aa9b8ebSad break;
1699aa9b8ebSad DELAY(1000);
1709aa9b8ebSad }
1719aa9b8ebSad
1729aa9b8ebSad cnt = dtkbd_process_msg(&msg, types, vals);
1739aa9b8ebSad i = 0;
1749aa9b8ebSad }
1759aa9b8ebSad
1769aa9b8ebSad *type = types[i++];
1779aa9b8ebSad *data = vals[i++];
1789aa9b8ebSad }
1799aa9b8ebSad
1809aa9b8ebSad void
dtkbd_cnpollc(void * v,int on)1819aa9b8ebSad dtkbd_cnpollc(void *v, int on)
1829aa9b8ebSad {
1839aa9b8ebSad
1849aa9b8ebSad /* XXX */
1859aa9b8ebSad }
1869aa9b8ebSad
1879aa9b8ebSad int
dtkbd_ioctl(void * v,u_long cmd,void * data,int flag,struct lwp * l)18853524e44Schristos dtkbd_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
1899aa9b8ebSad {
1909aa9b8ebSad
1919aa9b8ebSad switch (cmd) {
1929aa9b8ebSad case WSKBDIO_GTYPE:
1939aa9b8ebSad *(int *)data = WSKBD_TYPE_LK201;
1949aa9b8ebSad return 0;
1959aa9b8ebSad default:
1969aa9b8ebSad /* XXX */
197248d777dSmhitch return (EPASSTHROUGH);
1989aa9b8ebSad }
1999aa9b8ebSad }
2009aa9b8ebSad
2019aa9b8ebSad void
dtkbd_set_leds(void * v,int state)2029aa9b8ebSad dtkbd_set_leds(void *v, int state)
2039aa9b8ebSad {
2049aa9b8ebSad
2059aa9b8ebSad /* XXX */
2069aa9b8ebSad }
2079aa9b8ebSad
2089aa9b8ebSad void
dtkbd_handler(void * cookie,struct dt_msg * msg)209520489e1Sad dtkbd_handler(void *cookie, struct dt_msg *msg)
2109aa9b8ebSad {
2119aa9b8ebSad struct dtkbd_softc *sc;
2129aa9b8ebSad u_int types[20];
2139aa9b8ebSad int i, cnt, vals[20];
2149aa9b8ebSad
215520489e1Sad sc = cookie;
2169aa9b8ebSad
217520489e1Sad if (!sc->sc_enabled)
218520489e1Sad return;
219520489e1Sad
2209aa9b8ebSad cnt = dtkbd_process_msg(msg, types, vals);
2219aa9b8ebSad for (i = 0; i < cnt; i++)
222520489e1Sad wskbd_input(sc->sc_wskbddev, types[i], vals[i]);
2239aa9b8ebSad }
2249aa9b8ebSad
2259aa9b8ebSad int
dtkbd_process_msg(struct dt_msg * msg,u_int * types,int * vals)2269aa9b8ebSad dtkbd_process_msg(struct dt_msg *msg, u_int *types, int *vals)
2279aa9b8ebSad {
2289aa9b8ebSad u_int len, c, count;
2299aa9b8ebSad int i, j;
2309aa9b8ebSad
231520489e1Sad len = DT_CTL_LEN(msg->ctl);
2329aa9b8ebSad
2339aa9b8ebSad if ((msg->body[0] < DT_KBD_KEY_MIN && msg->body[0] != DT_KBD_EMPTY) ||
2349aa9b8ebSad len > 10) {
2359aa9b8ebSad printf("dtkbd0: error: %x %x %x\n", len, msg->body[0],
2369aa9b8ebSad msg->body[1]);
2379aa9b8ebSad
2389aa9b8ebSad /*
2399aa9b8ebSad * Fake an "all ups" to avoid the stuck key syndrome.
2409aa9b8ebSad */
2419aa9b8ebSad msg->body[0] = DT_KBD_EMPTY;
2429aa9b8ebSad len = 1;
2439aa9b8ebSad }
2449aa9b8ebSad
2459aa9b8ebSad if (msg->body[0] == DT_KBD_EMPTY) {
2469aa9b8ebSad types[0] = WSCONS_EVENT_ALL_KEYS_UP;
2479aa9b8ebSad vals[0] = 0;
2489aa9b8ebSad dtkbd_maplen = 0;
2499aa9b8ebSad return (1);
2509aa9b8ebSad }
2519aa9b8ebSad
2529aa9b8ebSad count = 0;
2539aa9b8ebSad
2549aa9b8ebSad for (i = 0; i < len; i++) {
2559aa9b8ebSad c = msg->body[i];
2569aa9b8ebSad
2579aa9b8ebSad for (j = 0; j < dtkbd_maplen; j++)
2589aa9b8ebSad if (dtkbd_map[j] == c)
2599aa9b8ebSad break;
2609aa9b8ebSad
2619aa9b8ebSad if (j == dtkbd_maplen) {
2629aa9b8ebSad types[count] = WSCONS_EVENT_KEY_DOWN;
2639aa9b8ebSad vals[count] = c - MIN_LK201_KEY;
2649aa9b8ebSad count++;
2659aa9b8ebSad }
2669aa9b8ebSad }
2679aa9b8ebSad
2689aa9b8ebSad for (j = 0; j < dtkbd_maplen; j++) {
2699aa9b8ebSad c = dtkbd_map[j];
2709aa9b8ebSad
2719aa9b8ebSad for (i = 0; i < len; i++)
2729aa9b8ebSad if (msg->body[i] == c)
2739aa9b8ebSad break;
2749aa9b8ebSad
2759aa9b8ebSad if (i == len) {
2769aa9b8ebSad types[count] = WSCONS_EVENT_KEY_UP;
2779aa9b8ebSad vals[count] = c - MIN_LK201_KEY;
2789aa9b8ebSad count++;
2799aa9b8ebSad }
2809aa9b8ebSad }
2819aa9b8ebSad
2829aa9b8ebSad memcpy(dtkbd_map, msg->body, len);
2839aa9b8ebSad dtkbd_maplen = len;
2849aa9b8ebSad
2859aa9b8ebSad return (count);
2869aa9b8ebSad }
287