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