1 /* $NetBSD: mkbd.c,v 1.17 2002/11/15 13:30:21 itohy 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/param.h> 36 #include <sys/device.h> 37 #include <sys/fcntl.h> 38 #include <sys/poll.h> 39 #include <sys/select.h> 40 #include <sys/proc.h> 41 #include <sys/signalvar.h> 42 #include <sys/systm.h> 43 44 #include "wskbd.h" 45 46 #include <dev/wscons/wsconsio.h> 47 #include <dev/wscons/wskbdvar.h> 48 #include <dev/wscons/wsksymdef.h> 49 #include <dev/wscons/wsksymvar.h> 50 51 #include <machine/cpu.h> 52 #include <machine/bus.h> 53 54 #include <dreamcast/dev/maple/maple.h> 55 #include <dreamcast/dev/maple/mapleconf.h> 56 #include <dreamcast/dev/maple/mkbdvar.h> 57 #include <dreamcast/dev/maple/mkbdmap.h> 58 59 /* 60 * Function declarations. 61 */ 62 static int mkbdmatch(struct device *, struct cfdata *, void *); 63 static void mkbdattach(struct device *, struct device *, void *); 64 static int mkbddetach(struct device *, int); 65 66 int mkbd_enable(void *, int); 67 void mkbd_set_leds(void *, int); 68 int mkbd_ioctl(void *, u_long, caddr_t, int, struct proc *); 69 70 struct wskbd_accessops mkbd_accessops = { 71 mkbd_enable, 72 mkbd_set_leds, 73 mkbd_ioctl, 74 }; 75 76 static void mkbd_intr(void *, struct maple_response *, int, int); 77 78 void mkbd_cngetc(void *, u_int *, int *); 79 void mkbd_cnpollc(void *, int); 80 int mkbd_cnattach(void); 81 82 struct wskbd_consops mkbd_consops = { 83 mkbd_cngetc, 84 mkbd_cnpollc, 85 }; 86 87 struct wskbd_mapdata mkbd_keymapdata = { 88 mkbd_keydesctab, 89 KB_JP, 90 }; 91 92 static struct mkbd_softc *mkbd_console_softc; 93 94 static int mkbd_is_console; 95 static int mkbd_console_initted; 96 97 CFATTACH_DECL(mkbd, sizeof(struct mkbd_softc), 98 mkbdmatch, mkbdattach, mkbddetach, NULL); 99 100 static int 101 mkbdmatch(struct device *parent, struct cfdata *cf, void *aux) 102 { 103 struct maple_attach_args *ma = aux; 104 105 return (ma->ma_function == MAPLE_FN_KEYBOARD ? MAPLE_MATCH_FUNC : 0); 106 } 107 108 static void 109 mkbdattach(struct device *parent, struct device *self, void *aux) 110 { 111 struct mkbd_softc *sc = (struct mkbd_softc *) self; 112 struct maple_attach_args *ma = aux; 113 #if NWSKBD > 0 114 struct wskbddev_attach_args a; 115 #endif 116 u_int32_t kbdtype; 117 118 sc->sc_parent = parent; 119 sc->sc_unit = ma->ma_unit; 120 121 kbdtype = maple_get_function_data(ma->ma_devinfo, 122 MAPLE_FN_KEYBOARD) >> 24; 123 switch (kbdtype) { 124 case 1: 125 printf(": Japanese keyboard"); 126 mkbd_keymapdata.layout = KB_JP; 127 break; 128 case 2: 129 printf(": US keyboard"); 130 mkbd_keymapdata.layout = KB_US; 131 break; 132 case 3: 133 printf(": European keyboard"); 134 mkbd_keymapdata.layout = KB_UK; 135 break; 136 default: 137 printf(": Unknown keyboard %d", kbdtype); 138 } 139 printf("\n"); 140 141 #if NWSKBD > 0 142 if ((a.console = mkbd_is_console) != 0) { 143 mkbd_is_console = 0; 144 if (!mkbd_console_initted) 145 wskbd_cnattach(&mkbd_consops, NULL, &mkbd_keymapdata); 146 mkbd_console_softc = sc; 147 } 148 a.keymap = &mkbd_keymapdata; 149 a.accessops = &mkbd_accessops; 150 a.accesscookie = sc; 151 sc->sc_wskbddev = config_found(self, &a, wskbddevprint); 152 #endif 153 154 maple_set_callback(parent, sc->sc_unit, MAPLE_FN_KEYBOARD, 155 mkbd_intr, sc); 156 maple_enable_periodic(parent, sc->sc_unit, MAPLE_FN_KEYBOARD, 1); 157 } 158 159 static int 160 mkbddetach(struct device *self, int flags) 161 { 162 struct mkbd_softc *sc = (struct mkbd_softc *) self; 163 int rv = 0; 164 165 if (sc == mkbd_console_softc) { 166 /* 167 * Hack to allow another Maple keyboard to be new console. 168 * XXX Should some other type device can be console. 169 */ 170 printf("%s: was console keyboard\n", sc->sc_dev.dv_xname); 171 wskbd_cndetach(); 172 mkbd_console_softc = NULL; 173 mkbd_console_initted = 0; 174 mkbd_is_console = 1; 175 } 176 if (sc->sc_wskbddev) 177 rv = config_detach(sc->sc_wskbddev, flags); 178 179 return rv; 180 } 181 182 int 183 mkbd_enable(void *v, int on) 184 { 185 186 return (0); 187 } 188 189 void 190 mkbd_set_leds(void *v, int on) 191 { 192 } 193 194 int 195 mkbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 196 { 197 198 switch (cmd) { 199 case WSKBDIO_GTYPE: 200 *(int *) data = WSKBD_TYPE_USB; /* XXX */ 201 return (0); 202 case WSKBDIO_SETLEDS: 203 return (0); 204 case WSKBDIO_GETLEDS: 205 *(int *) data = 0; 206 return (0); 207 case WSKBDIO_BELL: 208 case WSKBDIO_COMPLEXBELL: 209 return (0); 210 } 211 212 return (EPASSTHROUGH); 213 } 214 215 int 216 mkbd_cnattach() 217 { 218 219 wskbd_cnattach(&mkbd_consops, NULL, &mkbd_keymapdata); 220 mkbd_console_initted = 1; 221 mkbd_is_console = 1; 222 223 return (0); 224 } 225 226 static int polledkey; 227 extern int maple_polling; 228 229 #define SHIFT_KEYCODE_BASE 0xe0 230 #define UP_KEYCODE_FLAG 0x1000 231 232 #define KEY_UP(n) do { \ 233 if (maple_polling) \ 234 polledkey = (n)|UP_KEYCODE_FLAG; \ 235 else \ 236 wskbd_input(sc->sc_wskbddev, WSCONS_EVENT_KEY_UP, (n)); \ 237 } while (/*CONSTCOND*/0) 238 239 #define KEY_DOWN(n) do { \ 240 if (maple_polling) \ 241 polledkey = (n); \ 242 else \ 243 wskbd_input(sc->sc_wskbddev, WSCONS_EVENT_KEY_DOWN, (n)); \ 244 } while (/*CONSTCOND*/0) 245 246 #define SHIFT_UP(n) KEY_UP((n) | SHIFT_KEYCODE_BASE) 247 #define SHIFT_DOWN(n) KEY_DOWN((n) | SHIFT_KEYCODE_BASE) 248 249 static void 250 mkbd_intr(void *arg, struct maple_response *response, int sz, int flags) 251 { 252 struct mkbd_softc *sc = arg; 253 struct mkbd_condition *kbddata = (void *) response->data; 254 255 if ((flags & MAPLE_FLAG_PERIODIC) && 256 sz >= sizeof(struct mkbd_condition)) { 257 int i, j, v; 258 259 v = sc->sc_condition.shift & ~kbddata->shift; 260 if (v) 261 for (i = 0; i < 8; i++) 262 if (v & (1 << i)) 263 SHIFT_UP(i); 264 265 v = kbddata->shift & ~sc->sc_condition.shift; 266 if (v) 267 for (i = 0; i < 8; i++) 268 if (v & (1 << i)) 269 SHIFT_DOWN(i); 270 271 for (i = 0, j = 0; i < 6; i++) 272 if (sc->sc_condition.key[i] < 4) 273 break; 274 else if (sc->sc_condition.key[i] == kbddata->key[j]) 275 j++; 276 else 277 KEY_UP(sc->sc_condition.key[i]); 278 279 for (; j < 6; j++) 280 if (kbddata->key[j] < 4) 281 break; 282 else 283 KEY_DOWN(kbddata->key[j]); 284 285 memcpy(&sc->sc_condition, kbddata, 286 sizeof(struct mkbd_condition)); 287 } 288 } 289 290 void 291 mkbd_cngetc(void *v, u_int *type, int *data) 292 { 293 int key; 294 295 polledkey = -1; 296 maple_polling = 1; 297 while (polledkey == -1) { 298 if (mkbd_console_softc != NULL || 299 mkbd_console_softc->sc_parent != NULL) { 300 int t; 301 for (t = 0; t < 1000000; t++); 302 maple_run_polling(mkbd_console_softc->sc_parent); 303 } 304 } 305 maple_polling = 0; 306 key = polledkey; 307 308 *data = key & ~UP_KEYCODE_FLAG; 309 *type = (key & UP_KEYCODE_FLAG) ? 310 WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN; 311 } 312 313 void 314 mkbd_cnpollc(void *v, int on) 315 { 316 } 317