1 1.32 tsutsui /* $NetBSD: mkbd.c,v 1.32 2021/09/18 15:14:40 tsutsui Exp $ */ 2 1.1 marcus 3 1.2 marcus /*- 4 1.1 marcus * Copyright (c) 2001 Marcus Comstedt 5 1.1 marcus * All rights reserved. 6 1.1 marcus * 7 1.1 marcus * Redistribution and use in source and binary forms, with or without 8 1.1 marcus * modification, are permitted provided that the following conditions 9 1.1 marcus * are met: 10 1.1 marcus * 1. Redistributions of source code must retain the above copyright 11 1.1 marcus * notice, this list of conditions and the following disclaimer. 12 1.1 marcus * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 marcus * notice, this list of conditions and the following disclaimer in the 14 1.1 marcus * documentation and/or other materials provided with the distribution. 15 1.1 marcus * 3. All advertising materials mentioning features or use of this software 16 1.1 marcus * must display the following acknowledgement: 17 1.2 marcus * This product includes software developed by Marcus Comstedt. 18 1.2 marcus * 4. Neither the name of The NetBSD Foundation nor the names of its 19 1.2 marcus * contributors may be used to endorse or promote products derived 20 1.2 marcus * from this software without specific prior written permission. 21 1.1 marcus * 22 1.2 marcus * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 23 1.2 marcus * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 24 1.2 marcus * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25 1.2 marcus * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 26 1.2 marcus * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 1.2 marcus * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 1.2 marcus * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 1.2 marcus * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 1.2 marcus * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 1.2 marcus * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 1.2 marcus * POSSIBILITY OF SUCH DAMAGE. 33 1.1 marcus */ 34 1.19 lukem 35 1.19 lukem #include <sys/cdefs.h> 36 1.32 tsutsui __KERNEL_RCSID(0, "$NetBSD: mkbd.c,v 1.32 2021/09/18 15:14:40 tsutsui Exp $"); 37 1.1 marcus 38 1.1 marcus #include <sys/param.h> 39 1.1 marcus #include <sys/device.h> 40 1.1 marcus #include <sys/fcntl.h> 41 1.1 marcus #include <sys/poll.h> 42 1.1 marcus #include <sys/select.h> 43 1.1 marcus #include <sys/proc.h> 44 1.1 marcus #include <sys/signalvar.h> 45 1.1 marcus #include <sys/systm.h> 46 1.29 dyoung #include <sys/bus.h> 47 1.1 marcus 48 1.1 marcus #include "wskbd.h" 49 1.1 marcus 50 1.1 marcus #include <dev/wscons/wsconsio.h> 51 1.1 marcus #include <dev/wscons/wskbdvar.h> 52 1.1 marcus #include <dev/wscons/wsksymdef.h> 53 1.1 marcus #include <dev/wscons/wsksymvar.h> 54 1.1 marcus 55 1.1 marcus #include <machine/cpu.h> 56 1.1 marcus 57 1.1 marcus #include <dreamcast/dev/maple/maple.h> 58 1.1 marcus #include <dreamcast/dev/maple/mapleconf.h> 59 1.1 marcus #include <dreamcast/dev/maple/mkbdvar.h> 60 1.1 marcus #include <dreamcast/dev/maple/mkbdmap.h> 61 1.1 marcus 62 1.1 marcus /* 63 1.1 marcus * Function declarations. 64 1.1 marcus */ 65 1.28 tsutsui static int mkbdmatch(device_t, cfdata_t, void *); 66 1.28 tsutsui static void mkbdattach(device_t, device_t, void *); 67 1.28 tsutsui static int mkbddetach(device_t, int); 68 1.1 marcus 69 1.13 uch int mkbd_enable(void *, int); 70 1.13 uch void mkbd_set_leds(void *, int); 71 1.23 christos int mkbd_ioctl(void *, u_long, void *, int, struct lwp *); 72 1.1 marcus 73 1.1 marcus struct wskbd_accessops mkbd_accessops = { 74 1.1 marcus mkbd_enable, 75 1.1 marcus mkbd_set_leds, 76 1.1 marcus mkbd_ioctl, 77 1.1 marcus }; 78 1.1 marcus 79 1.17 itohy static void mkbd_intr(void *, struct maple_response *, int, int); 80 1.1 marcus 81 1.13 uch void mkbd_cngetc(void *, u_int *, int *); 82 1.13 uch void mkbd_cnpollc(void *, int); 83 1.13 uch int mkbd_cnattach(void); 84 1.1 marcus 85 1.1 marcus struct wskbd_consops mkbd_consops = { 86 1.1 marcus mkbd_cngetc, 87 1.1 marcus mkbd_cnpollc, 88 1.1 marcus }; 89 1.1 marcus 90 1.1 marcus struct wskbd_mapdata mkbd_keymapdata = { 91 1.1 marcus mkbd_keydesctab, 92 1.1 marcus KB_JP, 93 1.1 marcus }; 94 1.1 marcus 95 1.17 itohy static struct mkbd_softc *mkbd_console_softc; 96 1.1 marcus 97 1.17 itohy static int mkbd_is_console; 98 1.17 itohy static int mkbd_console_initted; 99 1.6 msaitoh 100 1.28 tsutsui CFATTACH_DECL_NEW(mkbd, sizeof(struct mkbd_softc), 101 1.17 itohy mkbdmatch, mkbdattach, mkbddetach, NULL); 102 1.1 marcus 103 1.1 marcus static int 104 1.28 tsutsui mkbdmatch(device_t parent, cfdata_t cf, void *aux) 105 1.1 marcus { 106 1.1 marcus struct maple_attach_args *ma = aux; 107 1.1 marcus 108 1.20 tsutsui return ma->ma_function == MAPLE_FN_KEYBOARD ? MAPLE_MATCH_FUNC : 0; 109 1.1 marcus } 110 1.1 marcus 111 1.1 marcus static void 112 1.28 tsutsui mkbdattach(device_t parent, device_t self, void *aux) 113 1.1 marcus { 114 1.28 tsutsui struct mkbd_softc *sc = device_private(self); 115 1.1 marcus struct maple_attach_args *ma = aux; 116 1.1 marcus #if NWSKBD > 0 117 1.1 marcus struct wskbddev_attach_args a; 118 1.1 marcus #endif 119 1.20 tsutsui uint32_t kbdtype; 120 1.1 marcus 121 1.28 tsutsui sc->sc_dev = self; 122 1.1 marcus sc->sc_parent = parent; 123 1.17 itohy sc->sc_unit = ma->ma_unit; 124 1.1 marcus 125 1.3 thorpej kbdtype = maple_get_function_data(ma->ma_devinfo, 126 1.17 itohy MAPLE_FN_KEYBOARD) >> 24; 127 1.10 thorpej switch (kbdtype) { 128 1.10 thorpej case 1: 129 1.10 thorpej printf(": Japanese keyboard"); 130 1.4 thorpej mkbd_keymapdata.layout = KB_JP; 131 1.10 thorpej break; 132 1.3 thorpej case 2: 133 1.5 thorpej printf(": US keyboard"); 134 1.4 thorpej mkbd_keymapdata.layout = KB_US; 135 1.3 thorpej break; 136 1.3 thorpej case 3: 137 1.5 thorpej printf(": European keyboard"); 138 1.4 thorpej mkbd_keymapdata.layout = KB_UK; 139 1.3 thorpej break; 140 1.3 thorpej default: 141 1.5 thorpej printf(": Unknown keyboard %d", kbdtype); 142 1.1 marcus } 143 1.1 marcus printf("\n"); 144 1.21 tsutsui #ifdef MKBD_LAYOUT 145 1.21 tsutsui /* allow user to override the default keymap */ 146 1.21 tsutsui mkbd_keymapdata.layout = MKBD_LAYOUT; 147 1.21 tsutsui #endif 148 1.21 tsutsui #ifdef MKBD_SWAPCTRLCAPS 149 1.21 tsutsui /* allow user to specify swapctrlcaps with the default keymap */ 150 1.21 tsutsui mkbd_keymapdata.layout |= KB_SWAPCTRLCAPS; 151 1.21 tsutsui #endif 152 1.1 marcus 153 1.1 marcus #if NWSKBD > 0 154 1.17 itohy if ((a.console = mkbd_is_console) != 0) { 155 1.17 itohy mkbd_is_console = 0; 156 1.17 itohy if (!mkbd_console_initted) 157 1.17 itohy wskbd_cnattach(&mkbd_consops, NULL, &mkbd_keymapdata); 158 1.17 itohy mkbd_console_softc = sc; 159 1.17 itohy } 160 1.1 marcus a.keymap = &mkbd_keymapdata; 161 1.1 marcus a.accessops = &mkbd_accessops; 162 1.1 marcus a.accesscookie = sc; 163 1.31 thorpej sc->sc_wskbddev = config_found(self, &a, wskbddevprint, CFARGS_NONE); 164 1.1 marcus #endif 165 1.1 marcus 166 1.17 itohy maple_set_callback(parent, sc->sc_unit, MAPLE_FN_KEYBOARD, 167 1.17 itohy mkbd_intr, sc); 168 1.17 itohy maple_enable_periodic(parent, sc->sc_unit, MAPLE_FN_KEYBOARD, 1); 169 1.1 marcus } 170 1.1 marcus 171 1.17 itohy static int 172 1.28 tsutsui mkbddetach(device_t self, int flags) 173 1.17 itohy { 174 1.28 tsutsui struct mkbd_softc *sc = device_private(self); 175 1.17 itohy int rv = 0; 176 1.17 itohy 177 1.17 itohy if (sc == mkbd_console_softc) { 178 1.17 itohy /* 179 1.17 itohy * Hack to allow another Maple keyboard to be new console. 180 1.17 itohy * XXX Should some other type device can be console. 181 1.17 itohy */ 182 1.28 tsutsui printf("%s: was console keyboard\n", device_xname(sc->sc_dev)); 183 1.17 itohy wskbd_cndetach(); 184 1.17 itohy mkbd_console_softc = NULL; 185 1.17 itohy mkbd_console_initted = 0; 186 1.17 itohy mkbd_is_console = 1; 187 1.17 itohy } 188 1.17 itohy if (sc->sc_wskbddev) 189 1.17 itohy rv = config_detach(sc->sc_wskbddev, flags); 190 1.1 marcus 191 1.17 itohy return rv; 192 1.17 itohy } 193 1.1 marcus 194 1.1 marcus int 195 1.13 uch mkbd_enable(void *v, int on) 196 1.1 marcus { 197 1.6 msaitoh 198 1.20 tsutsui return 0; 199 1.1 marcus } 200 1.1 marcus 201 1.1 marcus void 202 1.13 uch mkbd_set_leds(void *v, int on) 203 1.1 marcus { 204 1.1 marcus } 205 1.1 marcus 206 1.1 marcus int 207 1.23 christos mkbd_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l) 208 1.1 marcus { 209 1.6 msaitoh 210 1.1 marcus switch (cmd) { 211 1.1 marcus case WSKBDIO_GTYPE: 212 1.18 itohy *(int *) data = WSKBD_TYPE_MAPLE; 213 1.20 tsutsui return 0; 214 1.1 marcus case WSKBDIO_SETLEDS: 215 1.20 tsutsui return 0; 216 1.1 marcus case WSKBDIO_GETLEDS: 217 1.10 thorpej *(int *) data = 0; 218 1.20 tsutsui return 0; 219 1.1 marcus case WSKBDIO_COMPLEXBELL: 220 1.20 tsutsui return 0; 221 1.1 marcus } 222 1.1 marcus 223 1.20 tsutsui return EPASSTHROUGH; 224 1.1 marcus } 225 1.1 marcus 226 1.1 marcus int 227 1.20 tsutsui mkbd_cnattach(void) 228 1.1 marcus { 229 1.6 msaitoh 230 1.1 marcus wskbd_cnattach(&mkbd_consops, NULL, &mkbd_keymapdata); 231 1.6 msaitoh mkbd_console_initted = 1; 232 1.17 itohy mkbd_is_console = 1; 233 1.1 marcus 234 1.20 tsutsui return 0; 235 1.1 marcus } 236 1.1 marcus 237 1.1 marcus static int polledkey; 238 1.1 marcus extern int maple_polling; 239 1.1 marcus 240 1.7 marcus #define SHIFT_KEYCODE_BASE 0xe0 241 1.1 marcus #define UP_KEYCODE_FLAG 0x1000 242 1.1 marcus 243 1.13 uch #define KEY_UP(n) do { \ 244 1.13 uch if (maple_polling) \ 245 1.13 uch polledkey = (n)|UP_KEYCODE_FLAG; \ 246 1.13 uch else \ 247 1.13 uch wskbd_input(sc->sc_wskbddev, WSCONS_EVENT_KEY_UP, (n)); \ 248 1.13 uch } while (/*CONSTCOND*/0) 249 1.13 uch 250 1.13 uch #define KEY_DOWN(n) do { \ 251 1.13 uch if (maple_polling) \ 252 1.13 uch polledkey = (n); \ 253 1.13 uch else \ 254 1.11 atatat wskbd_input(sc->sc_wskbddev, WSCONS_EVENT_KEY_DOWN, (n)); \ 255 1.13 uch } while (/*CONSTCOND*/0) 256 1.1 marcus 257 1.13 uch #define SHIFT_UP(n) KEY_UP((n) | SHIFT_KEYCODE_BASE) 258 1.13 uch #define SHIFT_DOWN(n) KEY_DOWN((n) | SHIFT_KEYCODE_BASE) 259 1.1 marcus 260 1.1 marcus static void 261 1.17 itohy mkbd_intr(void *arg, struct maple_response *response, int sz, int flags) 262 1.1 marcus { 263 1.17 itohy struct mkbd_softc *sc = arg; 264 1.17 itohy struct mkbd_condition *kbddata = (void *) response->data; 265 1.6 msaitoh 266 1.17 itohy if ((flags & MAPLE_FLAG_PERIODIC) && 267 1.17 itohy sz >= sizeof(struct mkbd_condition)) { 268 1.10 thorpej int i, j, v; 269 1.1 marcus 270 1.10 thorpej v = sc->sc_condition.shift & ~kbddata->shift; 271 1.10 thorpej if (v) 272 1.10 thorpej for (i = 0; i < 8; i++) 273 1.10 thorpej if (v & (1 << i)) 274 1.10 thorpej SHIFT_UP(i); 275 1.10 thorpej 276 1.10 thorpej v = kbddata->shift & ~sc->sc_condition.shift; 277 1.10 thorpej if (v) 278 1.10 thorpej for (i = 0; i < 8; i++) 279 1.10 thorpej if (v & (1 << i)) 280 1.10 thorpej SHIFT_DOWN(i); 281 1.10 thorpej 282 1.10 thorpej for (i = 0, j = 0; i < 6; i++) 283 1.10 thorpej if (sc->sc_condition.key[i] < 4) 284 1.10 thorpej break; 285 1.10 thorpej else if (sc->sc_condition.key[i] == kbddata->key[j]) 286 1.10 thorpej j++; 287 1.10 thorpej else 288 1.10 thorpej KEY_UP(sc->sc_condition.key[i]); 289 1.10 thorpej 290 1.10 thorpej for (; j < 6; j++) 291 1.10 thorpej if (kbddata->key[j] < 4) 292 1.10 thorpej break; 293 1.10 thorpej else 294 1.10 thorpej KEY_DOWN(kbddata->key[j]); 295 1.1 marcus 296 1.10 thorpej memcpy(&sc->sc_condition, kbddata, 297 1.10 thorpej sizeof(struct mkbd_condition)); 298 1.1 marcus } 299 1.1 marcus } 300 1.1 marcus 301 1.1 marcus void 302 1.17 itohy mkbd_cngetc(void *v, u_int *type, int *data) 303 1.1 marcus { 304 1.1 marcus int key; 305 1.1 marcus 306 1.1 marcus polledkey = -1; 307 1.1 marcus maple_polling = 1; 308 1.10 thorpej while (polledkey == -1) { 309 1.24 marcus if (mkbd_console_softc != NULL && 310 1.10 thorpej mkbd_console_softc->sc_parent != NULL) { 311 1.26 marcus DELAY(20000); 312 1.10 thorpej maple_run_polling(mkbd_console_softc->sc_parent); 313 1.10 thorpej } 314 1.10 thorpej } 315 1.1 marcus maple_polling = 0; 316 1.1 marcus key = polledkey; 317 1.1 marcus 318 1.1 marcus *data = key & ~UP_KEYCODE_FLAG; 319 1.10 thorpej *type = (key & UP_KEYCODE_FLAG) ? 320 1.10 thorpej WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN; 321 1.1 marcus } 322 1.1 marcus 323 1.1 marcus void 324 1.13 uch mkbd_cnpollc(void *v, int on) 325 1.1 marcus { 326 1.1 marcus } 327