xref: /netbsd-src/sys/arch/epoc32/dev/epockbd.c (revision c7fb772b85b2b5d4cfb282f868f454b4701534fd)
1*c7fb772bSthorpej /*	$NetBSD: epockbd.c,v 1.5 2021/08/07 16:18:48 thorpej Exp $	*/
2d7b7d02eSkiyohara /*
3d7b7d02eSkiyohara  * Copyright (c) 2013 KIYOHARA Takashi
4d7b7d02eSkiyohara  * All rights reserved.
5d7b7d02eSkiyohara  *
6d7b7d02eSkiyohara  * Redistribution and use in source and binary forms, with or without
7d7b7d02eSkiyohara  * modification, are permitted provided that the following conditions
8d7b7d02eSkiyohara  * are met:
9d7b7d02eSkiyohara  * 1. Redistributions of source code must retain the above copyright
10d7b7d02eSkiyohara  *    notice, this list of conditions and the following disclaimer.
11d7b7d02eSkiyohara  * 2. Redistributions in binary form must reproduce the above copyright
12d7b7d02eSkiyohara  *    notice, this list of conditions and the following disclaimer in the
13d7b7d02eSkiyohara  *    documentation and/or other materials provided with the distribution.
14d7b7d02eSkiyohara  *
15d7b7d02eSkiyohara  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16d7b7d02eSkiyohara  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17d7b7d02eSkiyohara  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18d7b7d02eSkiyohara  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
19d7b7d02eSkiyohara  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20d7b7d02eSkiyohara  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21d7b7d02eSkiyohara  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22d7b7d02eSkiyohara  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
23d7b7d02eSkiyohara  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
24d7b7d02eSkiyohara  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25d7b7d02eSkiyohara  * POSSIBILITY OF SUCH DAMAGE.
26d7b7d02eSkiyohara  */
27d7b7d02eSkiyohara #include <sys/cdefs.h>
28*c7fb772bSthorpej __KERNEL_RCSID(0, "$NetBSD: epockbd.c,v 1.5 2021/08/07 16:18:48 thorpej Exp $");
29d7b7d02eSkiyohara 
30d7b7d02eSkiyohara #include <sys/param.h>
31d7b7d02eSkiyohara #include <sys/bus.h>
32d7b7d02eSkiyohara #include <sys/callout.h>
33d7b7d02eSkiyohara #include <sys/device.h>
34d7b7d02eSkiyohara #include <sys/errno.h>
35d7b7d02eSkiyohara #include <sys/kernel.h>
36d7b7d02eSkiyohara 
37d7b7d02eSkiyohara #include <dev/wscons/wsconsio.h>
38d7b7d02eSkiyohara #include <dev/wscons/wskbdvar.h>
39d7b7d02eSkiyohara #include <dev/wscons/wsksymdef.h>
40d7b7d02eSkiyohara #include <dev/wscons/wsksymvar.h>
41d7b7d02eSkiyohara 
42d7b7d02eSkiyohara #include <epoc32/dev/epockbdvar.h>
43d7b7d02eSkiyohara #include <epoc32/dev/epockbdmap.h>
44d7b7d02eSkiyohara 
45d7b7d02eSkiyohara #define EPOCKBD_COLUMN0		8
46d7b7d02eSkiyohara 
47d7b7d02eSkiyohara #define EPOCKBD_SCAN_READ(sc) \
48d7b7d02eSkiyohara 	bus_space_read_1((sc)->sc_scant, (sc)->sc_scanh, 0)
49d7b7d02eSkiyohara #define EPOCKBD_SCAN_WRITE(sc, cmd) \
50d7b7d02eSkiyohara 	bus_space_write_1((sc)->sc_scant, (sc)->sc_scanh, 0, (cmd))
51d7b7d02eSkiyohara #define EPOCKBD_DATA_READ(sc) \
52d7b7d02eSkiyohara 	bus_space_read_1((sc)->sc_datat, (sc)->sc_datah, 0)
53d7b7d02eSkiyohara 
54d7b7d02eSkiyohara #define EPOC2WS_KBD_DATA(r, c)	(((c) << 3) + (31 - __builtin_clz(r)) + 1)
55d7b7d02eSkiyohara 
56d7b7d02eSkiyohara static int epockbd_enable(void *, int);
57d7b7d02eSkiyohara static void epockbd_set_leds(void *, int);
58d7b7d02eSkiyohara static int epockbd_ioctl(void *, u_long, void *, int, struct lwp *);
59d7b7d02eSkiyohara 
60d7b7d02eSkiyohara static void epockbd_poll(void *);
61d7b7d02eSkiyohara 
62d7b7d02eSkiyohara static void epockbd_cngetc(void *, u_int *, int *);
63d7b7d02eSkiyohara static void epockbd_cnpollc(void *, int);
64d7b7d02eSkiyohara 
65d7b7d02eSkiyohara static struct wskbd_consops epockbd_consops = {
66d7b7d02eSkiyohara 	epockbd_cngetc,
67d7b7d02eSkiyohara 	epockbd_cnpollc,
68d7b7d02eSkiyohara 	NULL
69d7b7d02eSkiyohara };
70d7b7d02eSkiyohara 
71d7b7d02eSkiyohara static struct wskbd_accessops epockbd_accessops = {
72d7b7d02eSkiyohara 	epockbd_enable,
73d7b7d02eSkiyohara 	epockbd_set_leds,
74d7b7d02eSkiyohara 	epockbd_ioctl,
75d7b7d02eSkiyohara };
76d7b7d02eSkiyohara 
77d7b7d02eSkiyohara static struct wskbd_mapdata epockbd_mapdata = {
78d7b7d02eSkiyohara 	epockbd_keydesctab,
79d7b7d02eSkiyohara 	KB_UK,
80d7b7d02eSkiyohara };
81d7b7d02eSkiyohara 
82d7b7d02eSkiyohara static int is_console;
83d7b7d02eSkiyohara 
84d7b7d02eSkiyohara void
epockbd_attach(struct epockbd_softc * sc)85d7b7d02eSkiyohara epockbd_attach(struct epockbd_softc *sc)
86d7b7d02eSkiyohara {
87d7b7d02eSkiyohara 	struct wskbddev_attach_args aa;
88d7b7d02eSkiyohara 
89d7b7d02eSkiyohara 	aprint_normal("\n");
90d7b7d02eSkiyohara 	aprint_naive("\n");
91d7b7d02eSkiyohara 
92d7b7d02eSkiyohara 	if (is_console)
93d7b7d02eSkiyohara 		wskbd_cnattach(&epockbd_consops, sc, &epockbd_mapdata);
94d7b7d02eSkiyohara 
95d7b7d02eSkiyohara 	callout_init(&sc->sc_c, 0);
96d7b7d02eSkiyohara 	callout_reset(&sc->sc_c, hz, epockbd_poll, sc);
97d7b7d02eSkiyohara 	sc->sc_flags |= EPOCKBD_FLAG_ENABLE;
98d7b7d02eSkiyohara 
99d7b7d02eSkiyohara 	aa.console = is_console;
100d7b7d02eSkiyohara 	aa.keymap = &epockbd_mapdata;
101d7b7d02eSkiyohara 	aa.accessops = &epockbd_accessops;
102d7b7d02eSkiyohara 	aa.accesscookie = sc;
1032685996bSthorpej 	sc->sc_wskbddev = config_found(sc->sc_dev, &aa, wskbddevprint,
104*c7fb772bSthorpej 	    CFARGS_NONE);
105d7b7d02eSkiyohara }
106d7b7d02eSkiyohara 
107d7b7d02eSkiyohara /*
108d7b7d02eSkiyohara  * wskbd(9) functions
109d7b7d02eSkiyohara  */
110d7b7d02eSkiyohara 
111d7b7d02eSkiyohara static int
epockbd_enable(void * v,int on)112d7b7d02eSkiyohara epockbd_enable(void *v, int on)
113d7b7d02eSkiyohara {
114d7b7d02eSkiyohara 	struct epockbd_softc *sc = v;
115d7b7d02eSkiyohara 
116d7b7d02eSkiyohara 	if (on) {
117d7b7d02eSkiyohara 		sc->sc_flags |= EPOCKBD_FLAG_ENABLE;
118d7b7d02eSkiyohara 		callout_schedule(&sc->sc_c, hz / 20);
119d7b7d02eSkiyohara 	} else {
120d7b7d02eSkiyohara 		sc->sc_flags &= ~EPOCKBD_FLAG_ENABLE;
121d7b7d02eSkiyohara 		callout_stop(&sc->sc_c);
122d7b7d02eSkiyohara 	}
123d7b7d02eSkiyohara 	return 0;
124d7b7d02eSkiyohara }
125d7b7d02eSkiyohara 
126d7b7d02eSkiyohara static void
epockbd_set_leds(void * v,int on)127d7b7d02eSkiyohara epockbd_set_leds(void *v, int on)
128d7b7d02eSkiyohara {
129d7b7d02eSkiyohara 	/* Nothing */
130d7b7d02eSkiyohara }
131d7b7d02eSkiyohara 
132d7b7d02eSkiyohara static int
epockbd_ioctl(void * v,u_long cmd,void * data,int flag,struct lwp * l)133d7b7d02eSkiyohara epockbd_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
134d7b7d02eSkiyohara {
1354622a193Sskrll #ifdef WSDISPLAY_COMPAT_RAWKBD
1364622a193Sskrll 	struct epockbd_softc *sc = v;
1374622a193Sskrll #endif
138d7b7d02eSkiyohara 
139d7b7d02eSkiyohara 	switch (cmd) {
140d7b7d02eSkiyohara 	case WSKBDIO_GTYPE:
141d7b7d02eSkiyohara 		*(int *)data = WSKBD_TYPE_EPOC;
142d7b7d02eSkiyohara 		return 0;
143d7b7d02eSkiyohara 
144d7b7d02eSkiyohara 	case WSKBDIO_SETLEDS:
145d7b7d02eSkiyohara 		return 0;
146d7b7d02eSkiyohara 
147d7b7d02eSkiyohara 	case WSKBDIO_GETLEDS:
148d7b7d02eSkiyohara 		*(int *)data = 0;
149d7b7d02eSkiyohara 		return 0;
150d7b7d02eSkiyohara 
151d7b7d02eSkiyohara #ifdef WSDISPLAY_COMPAT_RAWKBD
152d7b7d02eSkiyohara 	case WSKBDIO_SETMODE:
1534622a193Sskrll 		*(int *)data = WSKBD_RAW;
154d7b7d02eSkiyohara 		sc->sc_flags |= EPOCKBD_FLAG_RAW;
155d7b7d02eSkiyohara 
156d7b7d02eSkiyohara 		/* Not yet...: return 0; */
157d7b7d02eSkiyohara #endif
158d7b7d02eSkiyohara 	}
159d7b7d02eSkiyohara 	return EPASSTHROUGH;
160d7b7d02eSkiyohara }
161d7b7d02eSkiyohara 
162d7b7d02eSkiyohara static void
epockbd_poll(void * v)163d7b7d02eSkiyohara epockbd_poll(void *v)
164d7b7d02eSkiyohara {
165d7b7d02eSkiyohara 	struct epockbd_softc *sc = v;
166d7b7d02eSkiyohara 	u_int type;
167d7b7d02eSkiyohara 	int data;
168d7b7d02eSkiyohara 
169d7b7d02eSkiyohara 	epockbd_cngetc(v, &type, &data);
170d7b7d02eSkiyohara 	if (data != 0)
171d7b7d02eSkiyohara 		wskbd_input(sc->sc_wskbddev, type, data);
172d7b7d02eSkiyohara 
173d7b7d02eSkiyohara 	callout_schedule(&sc->sc_c, hz / 20);
174d7b7d02eSkiyohara }
175d7b7d02eSkiyohara 
176d7b7d02eSkiyohara void
epockbd_cnattach(void)177d7b7d02eSkiyohara epockbd_cnattach(void)
178d7b7d02eSkiyohara {
179d7b7d02eSkiyohara 
180d7b7d02eSkiyohara 	is_console = 1;
181d7b7d02eSkiyohara }
182d7b7d02eSkiyohara 
183d7b7d02eSkiyohara static void
epockbd_cngetc(void * conscookie,u_int * type,int * data)184d7b7d02eSkiyohara epockbd_cngetc(void *conscookie, u_int *type, int *data)
185d7b7d02eSkiyohara {
186d7b7d02eSkiyohara 	struct epockbd_softc *sc = conscookie;
187d7b7d02eSkiyohara 	uint8_t cmd, key, mask;
188d7b7d02eSkiyohara 	int column, row;
189b43b39e4Skiyohara #if 1
190b43b39e4Skiyohara 	/*
191b43b39e4Skiyohara 	 * For some machines which return a strange response, it calculates
192b43b39e4Skiyohara 	 * using this variable.
193b43b39e4Skiyohara 	 */
194b43b39e4Skiyohara 	int pc = 0, pr = 0;
195b43b39e4Skiyohara #endif
196d7b7d02eSkiyohara 
197d7b7d02eSkiyohara 	*type = 0;
198d7b7d02eSkiyohara 	*data = 0;
199d7b7d02eSkiyohara 	mask = (1 << sc->sc_kbd_nrow) - 1;
200d7b7d02eSkiyohara 	for (column = 0; column < sc->sc_kbd_ncolumn; column++) {
201d7b7d02eSkiyohara 		delay(16);
202d7b7d02eSkiyohara 		cmd = EPOCKBD_SCAN_READ(sc);
203d7b7d02eSkiyohara 		cmd &= ~0xf;
204d7b7d02eSkiyohara 		cmd |= (EPOCKBD_COLUMN0 + column);
205d7b7d02eSkiyohara 		EPOCKBD_SCAN_WRITE(sc, cmd);
206d7b7d02eSkiyohara 		delay(16);
207d7b7d02eSkiyohara 		key = EPOCKBD_DATA_READ(sc) & mask;
208d7b7d02eSkiyohara 		if (sc->sc_state[column] != key) {
209d7b7d02eSkiyohara 			row = sc->sc_state[column] ^ key;
210d7b7d02eSkiyohara 			sc->sc_state[column] = key;
211b43b39e4Skiyohara #if 1
212b43b39e4Skiyohara 			if (*data == 0 ||
213b43b39e4Skiyohara 			    (row == pr && pc == 0 &&
214b43b39e4Skiyohara 			     column == sc->sc_kbd_ncolumn - 1))
215b43b39e4Skiyohara #else
216b43b39e4Skiyohara 			if (*data == 0)
217b43b39e4Skiyohara #endif
218b43b39e4Skiyohara 			{
219d7b7d02eSkiyohara 				if (key & row)
220d7b7d02eSkiyohara 					*type = WSCONS_EVENT_KEY_DOWN;
221d7b7d02eSkiyohara 				else
222d7b7d02eSkiyohara 					*type = WSCONS_EVENT_KEY_UP;
223d7b7d02eSkiyohara 				*data = EPOC2WS_KBD_DATA(row, column);
224b43b39e4Skiyohara #if 1
225b43b39e4Skiyohara 				pc = column;
226b43b39e4Skiyohara 				pr = row;
227b43b39e4Skiyohara #endif
228d7b7d02eSkiyohara 			}
229d7b7d02eSkiyohara 		}
230d7b7d02eSkiyohara 	}
231d7b7d02eSkiyohara }
232d7b7d02eSkiyohara 
233d7b7d02eSkiyohara /* ARGSUSED */
234d7b7d02eSkiyohara static void
epockbd_cnpollc(void * conckookie,int on)235d7b7d02eSkiyohara epockbd_cnpollc(void *conckookie, int on)
236d7b7d02eSkiyohara {
237d7b7d02eSkiyohara 	/* Nothing */
238d7b7d02eSkiyohara }
239