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