| Commit | Line | Data |
|---|---|---|
| 1550dfd9 MD |
1 | /* |
| 2 | * $FreeBSD: src/sys/dev/usb/ukbd.c,v 1.45 2003/10/04 21:41:01 joe Exp $ | |
| 74781d8f | 3 | * $DragonFly: src/sys/dev/usbmisc/ukbd/ukbd.c,v 1.27 2008/08/14 20:55:53 hasso Exp $ |
| 1550dfd9 | 4 | */ |
| 984263bc MD |
5 | |
| 6 | /* | |
| 7 | * Copyright (c) 1998 The NetBSD Foundation, Inc. | |
| 8 | * All rights reserved. | |
| 9 | * | |
| 10 | * This code is derived from software contributed to The NetBSD Foundation | |
| 11 | * by Lennart Augustsson (lennart@augustsson.net) at | |
| 12 | * Carlstedt Research & Technology. | |
| 13 | * | |
| 14 | * Redistribution and use in source and binary forms, with or without | |
| 15 | * modification, are permitted provided that the following conditions | |
| 16 | * are met: | |
| 17 | * 1. Redistributions of source code must retain the above copyright | |
| 18 | * notice, this list of conditions and the following disclaimer. | |
| 19 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 20 | * notice, this list of conditions and the following disclaimer in the | |
| 21 | * documentation and/or other materials provided with the distribution. | |
| 22 | * 3. All advertising materials mentioning features or use of this software | |
| 23 | * must display the following acknowledgement: | |
| 24 | * This product includes software developed by the NetBSD | |
| 25 | * Foundation, Inc. and its contributors. | |
| 26 | * 4. Neither the name of The NetBSD Foundation nor the names of its | |
| 27 | * contributors may be used to endorse or promote products derived | |
| 28 | * from this software without specific prior written permission. | |
| 29 | * | |
| 30 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |
| 31 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
| 32 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
| 33 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
| 34 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
| 35 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
| 36 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
| 37 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
| 38 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
| 39 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| 40 | * POSSIBILITY OF SUCH DAMAGE. | |
| 41 | */ | |
| 42 | ||
| 43 | /* | |
| 9a981cb9 | 44 | * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf |
| 984263bc MD |
45 | */ |
| 46 | ||
| 47 | #include "opt_kbd.h" | |
| 48 | #include "opt_ukbd.h" | |
| 49 | ||
| 50 | #include <sys/param.h> | |
| 51 | #include <sys/systm.h> | |
| 52 | #include <sys/kernel.h> | |
| 984263bc MD |
53 | #include <sys/module.h> |
| 54 | #include <sys/bus.h> | |
| 984263bc | 55 | #include <sys/file.h> |
| 1550dfd9 | 56 | #include <machine/limits.h> |
| 984263bc | 57 | #include <sys/select.h> |
| 984263bc | 58 | #include <sys/sysctl.h> |
| 4e01b467 | 59 | #include <sys/thread2.h> |
| 984263bc | 60 | |
| 1f2de5d4 MD |
61 | #include <bus/usb/usb.h> |
| 62 | #include <bus/usb/usbhid.h> | |
| 63 | #include <bus/usb/usbdi.h> | |
| 64 | #include <bus/usb/usbdi_util.h> | |
| 1f2de5d4 MD |
65 | #include <bus/usb/usb_quirks.h> |
| 66 | #include <bus/usb/hid.h> | |
| 984263bc MD |
67 | |
| 68 | #include <sys/kbio.h> | |
| 1f2de5d4 | 69 | #include <dev/misc/kbd/kbdreg.h> |
| 984263bc MD |
70 | |
| 71 | #define UKBD_EMULATE_ATSCANCODE 1 | |
| 72 | ||
| 73 | #define DRIVER_NAME "ukbd" | |
| 74 | ||
| 75 | #define delay(d) DELAY(d) | |
| 76 | ||
| 77 | #ifdef USB_DEBUG | |
| fc1ef497 HT |
78 | #define DPRINTF(x) if (ukbddebug) kprintf x |
| 79 | #define DPRINTFN(n,x) if (ukbddebug>(n)) kprintf x | |
| 984263bc MD |
80 | int ukbddebug = 0; |
| 81 | SYSCTL_NODE(_hw_usb, OID_AUTO, ukbd, CTLFLAG_RW, 0, "USB ukbd"); | |
| 82 | SYSCTL_INT(_hw_usb_ukbd, OID_AUTO, debug, CTLFLAG_RW, | |
| 83 | &ukbddebug, 0, "ukbd debug level"); | |
| 84 | #else | |
| 85 | #define DPRINTF(x) | |
| 86 | #define DPRINTFN(n,x) | |
| 87 | #endif | |
| 88 | ||
| 89 | #define UPROTO_BOOT_KEYBOARD 1 | |
| 90 | ||
| 91 | #define NKEYCODE 6 | |
| 92 | ||
| 93 | struct ukbd_data { | |
| 94 | u_int8_t modifiers; | |
| 95 | #define MOD_CONTROL_L 0x01 | |
| 96 | #define MOD_CONTROL_R 0x10 | |
| 97 | #define MOD_SHIFT_L 0x02 | |
| 98 | #define MOD_SHIFT_R 0x20 | |
| 99 | #define MOD_ALT_L 0x04 | |
| 100 | #define MOD_ALT_R 0x40 | |
| 101 | #define MOD_WIN_L 0x08 | |
| 102 | #define MOD_WIN_R 0x80 | |
| 103 | u_int8_t reserved; | |
| 104 | u_int8_t keycode[NKEYCODE]; | |
| 105 | }; | |
| 106 | ||
| 107 | #define MAXKEYS (NMOD+2*NKEYCODE) | |
| 108 | ||
| 109 | typedef struct ukbd_softc { | |
| 110 | device_t sc_dev; /* base device */ | |
| 111 | } ukbd_softc_t; | |
| 112 | ||
| 113 | #define UKBD_CHUNK 128 /* chunk size for read */ | |
| 114 | #define UKBD_BSIZE 1020 /* buffer size */ | |
| 115 | ||
| 116 | typedef void usbd_intr_t(usbd_xfer_handle, usbd_private_handle, usbd_status); | |
| 117 | typedef void usbd_disco_t(void *); | |
| 118 | ||
| 6ed427ca HT |
119 | static int ukbd_resume(device_t self); |
| 120 | static usbd_intr_t ukbd_intr; | |
| 121 | static int ukbd_driver_load(module_t mod, int what, void *arg); | |
| 122 | static int ukbd_default_term(keyboard_t *kbd); | |
| 0abf15af | 123 | |
| 6ed427ca | 124 | static keyboard_t default_kbd; |
| 984263bc | 125 | |
| 61b69189 HT |
126 | static device_probe_t ukbd_match; |
| 127 | static device_attach_t ukbd_attach; | |
| 128 | static device_detach_t ukbd_detach; | |
| 129 | ||
| 130 | static devclass_t ukbd_devclass; | |
| 131 | ||
| 132 | static kobj_method_t ukbd_methods[] = { | |
| 133 | DEVMETHOD(device_probe, ukbd_match), | |
| 134 | DEVMETHOD(device_attach, ukbd_attach), | |
| 135 | DEVMETHOD(device_detach, ukbd_detach), | |
| 136 | DEVMETHOD(device_resume, ukbd_resume), | |
| 137 | {0,0} | |
| 138 | }; | |
| 139 | ||
| 140 | static driver_t ukbd_driver = { | |
| 141 | "ukbd", | |
| 142 | ukbd_methods, | |
| 143 | sizeof(struct ukbd_softc) | |
| 144 | }; | |
| 145 | ||
| 146 | MODULE_DEPEND(ukbd, usb, 1, 1, 1); | |
| 984263bc | 147 | |
| e785a5d9 HT |
148 | static int |
| 149 | ukbd_match(device_t self) | |
| 984263bc | 150 | { |
| e785a5d9 | 151 | struct usb_attach_arg *uaa = device_get_ivars(self); |
| 984263bc MD |
152 | |
| 153 | keyboard_switch_t *sw; | |
| 154 | void *arg[2]; | |
| 155 | int unit = device_get_unit(self); | |
| 156 | ||
| 157 | sw = kbd_get_switch(DRIVER_NAME); | |
| 158 | if (sw == NULL) | |
| 159 | return (UMATCH_NONE); | |
| 160 | ||
| 161 | arg[0] = (void *)uaa; | |
| 162 | arg[1] = (void *)ukbd_intr; | |
| 163 | if ((*sw->probe)(unit, (void *)arg, 0)) | |
| 164 | return (UMATCH_NONE); | |
| 165 | ||
| 166 | return (UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO); | |
| 167 | } | |
| 168 | ||
| e785a5d9 HT |
169 | static int |
| 170 | ukbd_attach(device_t self) | |
| 984263bc | 171 | { |
| e785a5d9 HT |
172 | struct ukbd_softc *sc = device_get_softc(self); |
| 173 | struct usb_attach_arg *uaa = device_get_ivars(self); | |
| 984263bc MD |
174 | |
| 175 | keyboard_switch_t *sw; | |
| 176 | keyboard_t *kbd; | |
| 177 | void *arg[2]; | |
| 178 | int unit = device_get_unit(self); | |
| 179 | ||
| 180 | sw = kbd_get_switch(DRIVER_NAME); | |
| 181 | if (sw == NULL) | |
| e785a5d9 | 182 | return ENXIO; |
| 984263bc | 183 | |
| e785a5d9 | 184 | sc->sc_dev = self; |
| 984263bc MD |
185 | |
| 186 | arg[0] = (void *)uaa; | |
| 187 | arg[1] = (void *)ukbd_intr; | |
| 188 | kbd = NULL; | |
| 189 | if ((*sw->probe)(unit, (void *)arg, 0)) | |
| e785a5d9 | 190 | return ENXIO; |
| 984263bc | 191 | if ((*sw->init)(unit, &kbd, (void *)arg, 0)) |
| e785a5d9 | 192 | return ENXIO; |
| 984263bc MD |
193 | (*sw->enable)(kbd); |
| 194 | ||
| 195 | #ifdef KBD_INSTALL_CDEV | |
| 196 | if (kbd_attach(kbd)) | |
| e785a5d9 | 197 | return ENXIO; |
| 984263bc MD |
198 | #endif |
| 199 | if (bootverbose) | |
| 200 | (*sw->diag)(kbd, bootverbose); | |
| 201 | ||
| e785a5d9 | 202 | return 0; |
| 984263bc MD |
203 | } |
| 204 | ||
| 205 | int | |
| 206 | ukbd_detach(device_t self) | |
| 207 | { | |
| 208 | keyboard_t *kbd; | |
| 209 | int error; | |
| 210 | ||
| 211 | kbd = kbd_get_keyboard(kbd_find_keyboard(DRIVER_NAME, | |
| 212 | device_get_unit(self))); | |
| 213 | if (kbd == NULL) { | |
| 6ed427ca | 214 | DPRINTF(("%s: keyboard not attached!?\n", device_get_nameunit(self))); |
| 984263bc MD |
215 | return ENXIO; |
| 216 | } | |
| 217 | (*kbdsw[kbd->kb_index]->disable)(kbd); | |
| 218 | ||
| 219 | #ifdef KBD_INSTALL_CDEV | |
| 0abf15af MD |
220 | if (kbd != &default_kbd) { |
| 221 | error = kbd_detach(kbd); | |
| 222 | if (error) | |
| 223 | return error; | |
| 224 | } | |
| 984263bc | 225 | #endif |
| 0abf15af MD |
226 | if (kbd == &default_kbd) { |
| 227 | ukbd_default_term(kbd); | |
| 228 | } else { | |
| 229 | error = (*kbdsw[kbd->kb_index]->term)(kbd); | |
| 230 | if (error) | |
| 231 | return error; | |
| 232 | } | |
| 984263bc | 233 | |
| 6ed427ca | 234 | DPRINTF(("%s: disconnected\n", device_get_nameunit(self))); |
| 984263bc MD |
235 | |
| 236 | return (0); | |
| 237 | } | |
| 238 | ||
| 6ed427ca | 239 | static int |
| 984263bc MD |
240 | ukbd_resume(device_t self) |
| 241 | { | |
| 242 | keyboard_t *kbd; | |
| 243 | ||
| 244 | kbd = kbd_get_keyboard(kbd_find_keyboard(DRIVER_NAME, | |
| 245 | device_get_unit(self))); | |
| 246 | if (kbd) | |
| 247 | (*kbdsw[kbd->kb_index]->clear_state)(kbd); | |
| 248 | return (0); | |
| 249 | } | |
| 250 | ||
| 251 | void | |
| 252 | ukbd_intr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status) | |
| 253 | { | |
| 254 | keyboard_t *kbd = (keyboard_t *)addr; | |
| 255 | ||
| 256 | (*kbdsw[kbd->kb_index]->intr)(kbd, (void *)status); | |
| 257 | } | |
| 258 | ||
| 259 | DRIVER_MODULE(ukbd, uhub, ukbd_driver, ukbd_devclass, ukbd_driver_load, 0); | |
| 260 | ||
| 984263bc MD |
261 | |
| 262 | #define UKBD_DEFAULT 0 | |
| 263 | ||
| 264 | #define KEY_ERROR 0x01 | |
| 265 | ||
| 266 | #define KEY_PRESS 0 | |
| 267 | #define KEY_RELEASE 0x400 | |
| 268 | #define KEY_INDEX(c) ((c) & ~KEY_RELEASE) | |
| 269 | ||
| 270 | #define SCAN_PRESS 0 | |
| 271 | #define SCAN_RELEASE 0x80 | |
| 272 | #define SCAN_PREFIX_E0 0x100 | |
| 273 | #define SCAN_PREFIX_E1 0x200 | |
| 274 | #define SCAN_PREFIX_CTL 0x400 | |
| 275 | #define SCAN_PREFIX_SHIFT 0x800 | |
| 276 | #define SCAN_PREFIX (SCAN_PREFIX_E0 | SCAN_PREFIX_E1 | SCAN_PREFIX_CTL \ | |
| 277 | | SCAN_PREFIX_SHIFT) | |
| 278 | #define SCAN_CHAR(c) ((c) & 0x7f) | |
| 279 | ||
| 280 | #define NMOD 8 | |
| 6ed427ca | 281 | static struct { |
| 984263bc MD |
282 | int mask, key; |
| 283 | } ukbd_mods[NMOD] = { | |
| 284 | { MOD_CONTROL_L, 0xe0 }, | |
| 285 | { MOD_CONTROL_R, 0xe4 }, | |
| 286 | { MOD_SHIFT_L, 0xe1 }, | |
| 287 | { MOD_SHIFT_R, 0xe5 }, | |
| 288 | { MOD_ALT_L, 0xe2 }, | |
| 289 | { MOD_ALT_R, 0xe6 }, | |
| 290 | { MOD_WIN_L, 0xe3 }, | |
| 291 | { MOD_WIN_R, 0xe7 }, | |
| 292 | }; | |
| 293 | ||
| 294 | #define NN 0 /* no translation */ | |
| 1550dfd9 | 295 | /* |
| 984263bc MD |
296 | * Translate USB keycodes to AT keyboard scancodes. |
| 297 | */ | |
| 298 | /* | |
| 299 | * FIXME: Mac USB keyboard generates: | |
| 300 | * 0x53: keypad NumLock/Clear | |
| 301 | * 0x66: Power | |
| 302 | * 0x67: keypad = | |
| 303 | * 0x68: F13 | |
| 304 | * 0x69: F14 | |
| 305 | * 0x6a: F15 | |
| 306 | */ | |
| 6ed427ca | 307 | static u_int8_t ukbd_trtab[256] = { |
| 984263bc MD |
308 | 0, 0, 0, 0, 30, 48, 46, 32, /* 00 - 07 */ |
| 309 | 18, 33, 34, 35, 23, 36, 37, 38, /* 08 - 0F */ | |
| 310 | 50, 49, 24, 25, 16, 19, 31, 20, /* 10 - 17 */ | |
| 311 | 22, 47, 17, 45, 21, 44, 2, 3, /* 18 - 1F */ | |
| 312 | 4, 5, 6, 7, 8, 9, 10, 11, /* 20 - 27 */ | |
| 313 | 28, 1, 14, 15, 57, 12, 13, 26, /* 28 - 2F */ | |
| 314 | 27, 43, 43, 39, 40, 41, 51, 52, /* 30 - 37 */ | |
| 315 | 53, 58, 59, 60, 61, 62, 63, 64, /* 38 - 3F */ | |
| 316 | 65, 66, 67, 68, 87, 88, 92, 70, /* 40 - 47 */ | |
| 317 | 104, 102, 94, 96, 103, 99, 101, 98, /* 48 - 4F */ | |
| 318 | 97, 100, 95, 69, 91, 55, 74, 78, /* 50 - 57 */ | |
| 319 | 89, 79, 80, 81, 75, 76, 77, 71, /* 58 - 5F */ | |
| 320 | 72, 73, 82, 83, 86, 107, NN, NN, /* 60 - 67 */ | |
| 321 | NN, NN, NN, NN, NN, NN, NN, NN, /* 68 - 6F */ | |
| 322 | NN, NN, NN, NN, NN, NN, NN, NN, /* 70 - 77 */ | |
| 323 | NN, NN, NN, NN, NN, NN, NN, NN, /* 78 - 7F */ | |
| 324 | NN, NN, NN, NN, NN, NN, NN, 115, /* 80 - 87 */ | |
| 325 | 112, 125, 121, 123, NN, NN, NN, NN, /* 88 - 8F */ | |
| 326 | NN, NN, NN, NN, NN, NN, NN, NN, /* 90 - 97 */ | |
| 327 | NN, NN, NN, NN, NN, NN, NN, NN, /* 98 - 9F */ | |
| 328 | NN, NN, NN, NN, NN, NN, NN, NN, /* A0 - A7 */ | |
| 329 | NN, NN, NN, NN, NN, NN, NN, NN, /* A8 - AF */ | |
| 330 | NN, NN, NN, NN, NN, NN, NN, NN, /* B0 - B7 */ | |
| 331 | NN, NN, NN, NN, NN, NN, NN, NN, /* B8 - BF */ | |
| 332 | NN, NN, NN, NN, NN, NN, NN, NN, /* C0 - C7 */ | |
| 333 | NN, NN, NN, NN, NN, NN, NN, NN, /* C8 - CF */ | |
| 334 | NN, NN, NN, NN, NN, NN, NN, NN, /* D0 - D7 */ | |
| 335 | NN, NN, NN, NN, NN, NN, NN, NN, /* D8 - DF */ | |
| 336 | 29, 42, 56, 105, 90, 54, 93, 106, /* E0 - E7 */ | |
| 337 | NN, NN, NN, NN, NN, NN, NN, NN, /* E8 - EF */ | |
| 338 | NN, NN, NN, NN, NN, NN, NN, NN, /* F0 - F7 */ | |
| 339 | NN, NN, NN, NN, NN, NN, NN, NN, /* F8 - FF */ | |
| 340 | }; | |
| 341 | ||
| 342 | typedef struct ukbd_state { | |
| 343 | usbd_interface_handle ks_iface; /* interface */ | |
| 344 | usbd_pipe_handle ks_intrpipe; /* interrupt pipe */ | |
| 345 | struct usb_attach_arg *ks_uaa; | |
| 346 | int ks_ep_addr; | |
| 347 | ||
| 348 | struct ukbd_data ks_ndata; | |
| 349 | struct ukbd_data ks_odata; | |
| 350 | u_long ks_ntime[NKEYCODE]; | |
| 351 | u_long ks_otime[NKEYCODE]; | |
| 352 | ||
| 353 | #define INPUTBUFSIZE (NMOD + 2*NKEYCODE) | |
| 354 | u_int ks_input[INPUTBUFSIZE]; /* input buffer */ | |
| 355 | int ks_inputs; | |
| 356 | int ks_inputhead; | |
| 357 | int ks_inputtail; | |
| 358 | ||
| 359 | int ks_ifstate; | |
| 360 | #define INTRENABLED (1 << 0) | |
| 361 | #define DISCONNECTED (1 << 1) | |
| 362 | ||
| ee332a5a | 363 | struct callout ks_timeout; |
| 984263bc MD |
364 | |
| 365 | int ks_mode; /* input mode (K_XLATE,K_RAW,K_CODE) */ | |
| 366 | int ks_flags; /* flags */ | |
| 367 | #define COMPOSE (1 << 0) | |
| 368 | int ks_polling; | |
| 369 | int ks_state; /* shift/lock key state */ | |
| 370 | int ks_accents; /* accent key index (> 0) */ | |
| 371 | u_int ks_composed_char; /* composed char code (> 0) */ | |
| 372 | #ifdef UKBD_EMULATE_ATSCANCODE | |
| 373 | u_int ks_buffered_char[2]; | |
| 374 | #endif | |
| 375 | } ukbd_state_t; | |
| 376 | ||
| 377 | /* keyboard driver declaration */ | |
| 6ed427ca HT |
378 | static int ukbd_configure(int flags); |
| 379 | static kbd_probe_t ukbd_probe; | |
| 380 | static kbd_init_t ukbd_init; | |
| 381 | static kbd_term_t ukbd_term; | |
| 382 | static kbd_intr_t ukbd_interrupt; | |
| 383 | static kbd_test_if_t ukbd_test_if; | |
| 384 | static kbd_enable_t ukbd_enable; | |
| 385 | static kbd_disable_t ukbd_disable; | |
| 386 | static kbd_read_t ukbd_read; | |
| 387 | static kbd_check_t ukbd_check; | |
| 388 | static kbd_read_char_t ukbd_read_char; | |
| 389 | static kbd_check_char_t ukbd_check_char; | |
| 390 | static kbd_ioctl_t ukbd_ioctl; | |
| 391 | static kbd_lock_t ukbd_lock; | |
| 392 | static kbd_clear_state_t ukbd_clear_state; | |
| 393 | static kbd_get_state_t ukbd_get_state; | |
| 394 | static kbd_set_state_t ukbd_set_state; | |
| 395 | static kbd_poll_mode_t ukbd_poll; | |
| 984263bc MD |
396 | |
| 397 | keyboard_switch_t ukbdsw = { | |
| 398 | ukbd_probe, | |
| 399 | ukbd_init, | |
| 400 | ukbd_term, | |
| 401 | ukbd_interrupt, | |
| 402 | ukbd_test_if, | |
| 403 | ukbd_enable, | |
| 404 | ukbd_disable, | |
| 405 | ukbd_read, | |
| 406 | ukbd_check, | |
| 407 | ukbd_read_char, | |
| 408 | ukbd_check_char, | |
| 409 | ukbd_ioctl, | |
| 410 | ukbd_lock, | |
| 411 | ukbd_clear_state, | |
| 412 | ukbd_get_state, | |
| 413 | ukbd_set_state, | |
| 414 | genkbd_get_fkeystr, | |
| 415 | ukbd_poll, | |
| 416 | genkbd_diag, | |
| 417 | }; | |
| 418 | ||
| 419 | KEYBOARD_DRIVER(ukbd, ukbdsw, ukbd_configure); | |
| 420 | ||
| 421 | /* local functions */ | |
| 6ed427ca | 422 | static int ukbd_enable_intr(keyboard_t *kbd, int on, |
| 984263bc | 423 | usbd_intr_t *func); |
| 6ed427ca | 424 | static timeout_t ukbd_timeout; |
| 984263bc | 425 | |
| 6ed427ca HT |
426 | static int ukbd_getc(ukbd_state_t *state); |
| 427 | static int probe_keyboard(struct usb_attach_arg *uaa, int flags); | |
| 428 | static int init_keyboard(ukbd_state_t *state, int *type, | |
| 984263bc | 429 | int flags); |
| 6ed427ca HT |
430 | static void set_leds(ukbd_state_t *state, int leds); |
| 431 | static int set_typematic(keyboard_t *kbd, int code); | |
| 984263bc | 432 | #ifdef UKBD_EMULATE_ATSCANCODE |
| 6ed427ca | 433 | static int keycode2scancode(int keycode, int shift, int up); |
| 984263bc MD |
434 | #endif |
| 435 | ||
| 436 | /* local variables */ | |
| 437 | ||
| 438 | /* the initial key map, accent map and fkey strings */ | |
| 271d192a | 439 | #if defined(UKBD_DFLT_KEYMAP) && !defined(KLD_MODULE) |
| 984263bc MD |
440 | #define KBD_DFLT_KEYMAP |
| 441 | #include "ukbdmap.h" | |
| 442 | #endif | |
| 1f2de5d4 | 443 | #include <dev/misc/kbd/kbdtables.h> |
| 984263bc MD |
444 | |
| 445 | /* structures for the default keyboard */ | |
| 6ed427ca HT |
446 | static ukbd_state_t default_kbd_state; |
| 447 | static keymap_t default_keymap; | |
| 448 | static accentmap_t default_accentmap; | |
| 449 | static fkeytab_t default_fkeytab[NUM_FKEYS]; | |
| 984263bc | 450 | |
| 1550dfd9 | 451 | /* |
| 984263bc MD |
452 | * The back door to the keyboard driver! |
| 453 | * This function is called by the console driver, via the kbdio module, | |
| 454 | * to tickle keyboard drivers when the low-level console is being initialized. | |
| 455 | * Almost nothing in the kernel has been initialied yet. Try to probe | |
| 456 | * keyboards if possible. | |
| 457 | * NOTE: because of the way the low-level conole is initialized, this routine | |
| 458 | * may be called more than once!! | |
| 459 | */ | |
| 6ed427ca | 460 | static int |
| 984263bc MD |
461 | ukbd_configure(int flags) |
| 462 | { | |
| 463 | return 0; | |
| 464 | ||
| 465 | #if 0 /* not yet */ | |
| 466 | keyboard_t *kbd; | |
| 467 | device_t device; | |
| 468 | struct usb_attach_arg *uaa; | |
| 469 | void *arg[2]; | |
| 470 | ||
| 471 | device = devclass_get_device(ukbd_devclass, UKBD_DEFAULT); | |
| 472 | if (device == NULL) | |
| 473 | return 0; | |
| 474 | uaa = (struct usb_attach_arg *)device_get_ivars(device); | |
| 475 | if (uaa == NULL) | |
| 476 | return 0; | |
| 477 | ||
| 478 | /* probe the default keyboard */ | |
| 479 | arg[0] = (void *)uaa; | |
| 480 | arg[1] = (void *)ukbd_intr; | |
| 481 | kbd = NULL; | |
| 482 | if (ukbd_probe(UKBD_DEFAULT, arg, flags)) | |
| 483 | return 0; | |
| 484 | if (ukbd_init(UKBD_DEFAULT, &kbd, arg, flags)) | |
| 485 | return 0; | |
| 486 | ||
| 487 | /* return the number of found keyboards */ | |
| 488 | return 1; | |
| 489 | #endif | |
| 490 | } | |
| 491 | ||
| 492 | /* low-level functions */ | |
| 493 | ||
| 494 | /* detect a keyboard */ | |
| 6ed427ca | 495 | static int |
| 984263bc MD |
496 | ukbd_probe(int unit, void *arg, int flags) |
| 497 | { | |
| 498 | void **data; | |
| 499 | struct usb_attach_arg *uaa; | |
| 500 | ||
| 501 | data = (void **)arg; | |
| 502 | uaa = (struct usb_attach_arg *)data[0]; | |
| 503 | ||
| 984263bc MD |
504 | if (unit == UKBD_DEFAULT) { |
| 505 | if (KBD_IS_PROBED(&default_kbd)) | |
| 506 | return 0; | |
| 507 | } | |
| 508 | if (probe_keyboard(uaa, flags)) | |
| 509 | return ENXIO; | |
| 510 | return 0; | |
| 511 | } | |
| 512 | ||
| 0abf15af MD |
513 | /* |
| 514 | * Reset and initialize the device. Note that unit 0 (UKBD_DEFAULT) is an | |
| 515 | * always-connected device once it has been initially detected. We do not | |
| 516 | * deregister it if the usb keyboard is unplugged to avoid losing the | |
| 517 | * connection to the console. This feature also handles the USB bus reset | |
| 518 | * which detaches and reattaches USB devices during boot. | |
| 519 | */ | |
| 6ed427ca | 520 | static int |
| 984263bc MD |
521 | ukbd_init(int unit, keyboard_t **kbdp, void *arg, int flags) |
| 522 | { | |
| 523 | keyboard_t *kbd; | |
| 524 | ukbd_state_t *state; | |
| 525 | keymap_t *keymap; | |
| 526 | accentmap_t *accmap; | |
| 527 | fkeytab_t *fkeymap; | |
| 528 | int fkeymap_size; | |
| 529 | void **data = (void **)arg; | |
| 530 | struct usb_attach_arg *uaa = (struct usb_attach_arg *)data[0]; | |
| 531 | ||
| 984263bc MD |
532 | if (unit == UKBD_DEFAULT) { |
| 533 | *kbdp = kbd = &default_kbd; | |
| 534 | if (KBD_IS_INITIALIZED(kbd) && KBD_IS_CONFIGURED(kbd)) | |
| 535 | return 0; | |
| 536 | state = &default_kbd_state; | |
| 537 | keymap = &default_keymap; | |
| 538 | accmap = &default_accentmap; | |
| 539 | fkeymap = default_fkeytab; | |
| 540 | fkeymap_size = | |
| 541 | sizeof(default_fkeytab)/sizeof(default_fkeytab[0]); | |
| 542 | } else if (*kbdp == NULL) { | |
| efda3bd0 MD |
543 | *kbdp = kbd = kmalloc(sizeof(*kbd), M_DEVBUF, M_INTWAIT | M_ZERO); |
| 544 | state = kmalloc(sizeof(*state), M_DEVBUF, M_INTWAIT); | |
| 545 | keymap = kmalloc(sizeof(key_map), M_DEVBUF, M_INTWAIT); | |
| 546 | accmap = kmalloc(sizeof(accent_map), M_DEVBUF, M_INTWAIT); | |
| 547 | fkeymap = kmalloc(sizeof(fkey_tab), M_DEVBUF, M_INTWAIT); | |
| 984263bc MD |
548 | fkeymap_size = sizeof(fkey_tab)/sizeof(fkey_tab[0]); |
| 549 | if ((state == NULL) || (keymap == NULL) || (accmap == NULL) | |
| 550 | || (fkeymap == NULL)) { | |
| 551 | if (state != NULL) | |
| efda3bd0 | 552 | kfree(state, M_DEVBUF); |
| 984263bc | 553 | if (keymap != NULL) |
| efda3bd0 | 554 | kfree(keymap, M_DEVBUF); |
| 984263bc | 555 | if (accmap != NULL) |
| efda3bd0 | 556 | kfree(accmap, M_DEVBUF); |
| 984263bc | 557 | if (fkeymap != NULL) |
| efda3bd0 MD |
558 | kfree(fkeymap, M_DEVBUF); |
| 559 | kfree(kbd, M_DEVBUF); | |
| 984263bc MD |
560 | return ENOMEM; |
| 561 | } | |
| 562 | } else if (KBD_IS_INITIALIZED(*kbdp) && KBD_IS_CONFIGURED(*kbdp)) { | |
| 563 | return 0; | |
| 564 | } else { | |
| 565 | kbd = *kbdp; | |
| 566 | state = (ukbd_state_t *)kbd->kb_data; | |
| 567 | keymap = kbd->kb_keymap; | |
| 568 | accmap = kbd->kb_accentmap; | |
| 569 | fkeymap = kbd->kb_fkeytab; | |
| 570 | fkeymap_size = kbd->kb_fkeytab_size; | |
| 571 | } | |
| 572 | ||
| 573 | if (!KBD_IS_PROBED(kbd)) { | |
| 0abf15af MD |
574 | if (KBD_IS_CONFIGURED(kbd)) { |
| 575 | kbd_reinit_struct(kbd, flags, KB_PRI_USB); | |
| 576 | } else { | |
| 577 | kbd_init_struct(kbd, DRIVER_NAME, KB_OTHER, | |
| 578 | unit, flags, KB_PRI_USB, | |
| 579 | 0, 0); | |
| 580 | } | |
| 984263bc MD |
581 | bzero(state, sizeof(*state)); |
| 582 | bcopy(&key_map, keymap, sizeof(key_map)); | |
| 583 | bcopy(&accent_map, accmap, sizeof(accent_map)); | |
| 584 | bcopy(fkey_tab, fkeymap, | |
| 585 | imin(fkeymap_size*sizeof(fkeymap[0]), sizeof(fkey_tab))); | |
| 586 | kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size); | |
| 587 | kbd->kb_data = (void *)state; | |
| 588 | ||
| 589 | if (probe_keyboard(uaa, flags)) | |
| 590 | return ENXIO; | |
| 591 | else | |
| 592 | KBD_FOUND_DEVICE(kbd); | |
| 593 | ukbd_clear_state(kbd); | |
| de8716a3 MD |
594 | |
| 595 | /* | |
| fcd74d1b MD |
596 | * If reattatching to an already open keyboard (e.g. console), |
| 597 | * try to restore the translation mode. Otherwise set the | |
| 598 | * translation mode to, well, translation mode so we don't | |
| 599 | * get garbage. | |
| de8716a3 | 600 | */ |
| fcd74d1b | 601 | if (!KBD_IS_CONFIGURED(kbd)) { |
| de8716a3 | 602 | state->ks_mode = K_XLATE; |
| fcd74d1b MD |
603 | kbd->kb_savemode = state->ks_mode; |
| 604 | } else { | |
| 605 | state->ks_mode = kbd->kb_savemode; | |
| 606 | } | |
| 984263bc MD |
607 | state->ks_iface = uaa->iface; |
| 608 | state->ks_uaa = uaa; | |
| 609 | state->ks_ifstate = 0; | |
| ee332a5a | 610 | callout_init(&state->ks_timeout); |
| 1550dfd9 | 611 | /* |
| 984263bc MD |
612 | * FIXME: set the initial value for lock keys in ks_state |
| 613 | * according to the BIOS data? | |
| 614 | */ | |
| 615 | KBD_PROBE_DONE(kbd); | |
| 616 | } | |
| 617 | if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) { | |
| 618 | if (KBD_HAS_DEVICE(kbd) | |
| 619 | && init_keyboard((ukbd_state_t *)kbd->kb_data, | |
| 620 | &kbd->kb_type, kbd->kb_flags)) | |
| 621 | return ENXIO; | |
| 622 | ukbd_ioctl(kbd, KDSETLED, (caddr_t)&(state->ks_state)); | |
| 984263bc MD |
623 | } |
| 624 | if (!KBD_IS_CONFIGURED(kbd)) { | |
| 625 | if (kbd_register(kbd) < 0) | |
| 626 | return ENXIO; | |
| 0abf15af MD |
627 | KBD_CONFIG_DONE(kbd); |
| 628 | } | |
| 629 | if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) { | |
| 984263bc MD |
630 | if (ukbd_enable_intr(kbd, TRUE, (usbd_intr_t *)data[1]) == 0) |
| 631 | ukbd_timeout((void *)kbd); | |
| 0abf15af | 632 | KBD_INIT_DONE(kbd); |
| 984263bc | 633 | } |
| 984263bc MD |
634 | return 0; |
| 635 | } | |
| 636 | ||
| 6ed427ca | 637 | static int |
| 984263bc MD |
638 | ukbd_enable_intr(keyboard_t *kbd, int on, usbd_intr_t *func) |
| 639 | { | |
| 640 | ukbd_state_t *state = (ukbd_state_t *)kbd->kb_data; | |
| 641 | usbd_status err; | |
| 642 | ||
| 643 | if (on) { | |
| 644 | /* Set up interrupt pipe. */ | |
| 645 | if (state->ks_ifstate & INTRENABLED) | |
| 646 | return EBUSY; | |
| 1550dfd9 | 647 | |
| 984263bc | 648 | state->ks_ifstate |= INTRENABLED; |
| 1550dfd9 | 649 | err = usbd_open_pipe_intr(state->ks_iface, state->ks_ep_addr, |
| f32bdd67 | 650 | USBD_SHORT_XFER_OK | USBD_CALLBACK_LAST, |
| 984263bc | 651 | &state->ks_intrpipe, kbd, |
| 1550dfd9 | 652 | &state->ks_ndata, |
| 984263bc MD |
653 | sizeof(state->ks_ndata), func, |
| 654 | USBD_DEFAULT_INTERVAL); | |
| 655 | if (err) | |
| 656 | return (EIO); | |
| 657 | } else { | |
| 658 | /* Disable interrupts. */ | |
| 659 | usbd_abort_pipe(state->ks_intrpipe); | |
| 660 | usbd_close_pipe(state->ks_intrpipe); | |
| 661 | ||
| 662 | state->ks_ifstate &= ~INTRENABLED; | |
| 663 | } | |
| 664 | ||
| 665 | return (0); | |
| 666 | } | |
| 667 | ||
| 668 | /* finish using this keyboard */ | |
| 6ed427ca | 669 | static int |
| 984263bc MD |
670 | ukbd_term(keyboard_t *kbd) |
| 671 | { | |
| 672 | ukbd_state_t *state; | |
| 673 | int error; | |
| 984263bc | 674 | |
| 4e01b467 | 675 | crit_enter(); |
| 984263bc MD |
676 | state = (ukbd_state_t *)kbd->kb_data; |
| 677 | DPRINTF(("ukbd_term: ks_ifstate=0x%x\n", state->ks_ifstate)); | |
| 678 | ||
| ee332a5a | 679 | callout_stop(&state->ks_timeout); |
| 984263bc MD |
680 | |
| 681 | if (state->ks_ifstate & INTRENABLED) | |
| 682 | ukbd_enable_intr(kbd, FALSE, NULL); | |
| 683 | if (state->ks_ifstate & INTRENABLED) { | |
| 4e01b467 | 684 | crit_exit(); |
| 984263bc MD |
685 | DPRINTF(("ukbd_term: INTRENABLED!\n")); |
| 686 | return ENXIO; | |
| 687 | } | |
| 688 | ||
| 689 | error = kbd_unregister(kbd); | |
| 690 | DPRINTF(("ukbd_term: kbd_unregister() %d\n", error)); | |
| 691 | if (error == 0) { | |
| 692 | kbd->kb_flags = 0; | |
| 693 | if (kbd != &default_kbd) { | |
| efda3bd0 MD |
694 | kfree(kbd->kb_keymap, M_DEVBUF); |
| 695 | kfree(kbd->kb_accentmap, M_DEVBUF); | |
| 696 | kfree(kbd->kb_fkeytab, M_DEVBUF); | |
| 697 | kfree(state, M_DEVBUF); | |
| 698 | kfree(kbd, M_DEVBUF); | |
| 984263bc MD |
699 | } |
| 700 | } | |
| 4e01b467 | 701 | crit_exit(); |
| 984263bc MD |
702 | return error; |
| 703 | } | |
| 704 | ||
| 0abf15af MD |
705 | /* |
| 706 | * Finish using the default keyboard. Shutdown the USB side of the keyboard | |
| 707 | * but do not unregister it. | |
| 708 | */ | |
| 6ed427ca | 709 | static int |
| 0abf15af MD |
710 | ukbd_default_term(keyboard_t *kbd) |
| 711 | { | |
| 712 | ukbd_state_t *state; | |
| 0abf15af | 713 | |
| 4e01b467 | 714 | crit_enter(); |
| 0abf15af MD |
715 | |
| 716 | state = (ukbd_state_t *)kbd->kb_data; | |
| 717 | DPRINTF(("ukbd_default_term: ks_ifstate=0x%x\n", state->ks_ifstate)); | |
| 718 | ||
| ee332a5a | 719 | callout_stop(&state->ks_timeout); |
| 0abf15af MD |
720 | |
| 721 | if (state->ks_ifstate & INTRENABLED) | |
| 722 | ukbd_enable_intr(kbd, FALSE, NULL); | |
| 723 | if (state->ks_ifstate & INTRENABLED) { | |
| 4e01b467 | 724 | crit_exit(); |
| 0abf15af MD |
725 | DPRINTF(("ukbd_term: INTRENABLED!\n")); |
| 726 | return ENXIO; | |
| 727 | } | |
| 728 | KBD_LOST_DEVICE(kbd); | |
| 729 | KBD_LOST_PROBE(kbd); | |
| 730 | KBD_LOST_INIT(kbd); | |
| 4e01b467 | 731 | crit_exit(); |
| 0abf15af MD |
732 | return (0); |
| 733 | } | |
| 984263bc MD |
734 | |
| 735 | /* keyboard interrupt routine */ | |
| 736 | ||
| 6ed427ca | 737 | static void |
| 984263bc MD |
738 | ukbd_timeout(void *arg) |
| 739 | { | |
| 740 | keyboard_t *kbd; | |
| 741 | ukbd_state_t *state; | |
| 984263bc MD |
742 | |
| 743 | kbd = (keyboard_t *)arg; | |
| 744 | state = (ukbd_state_t *)kbd->kb_data; | |
| 4e01b467 | 745 | crit_enter(); |
| 984263bc | 746 | (*kbdsw[kbd->kb_index]->intr)(kbd, (void *)USBD_NORMAL_COMPLETION); |
| ee332a5a | 747 | callout_reset(&state->ks_timeout, hz / 40, ukbd_timeout, arg); |
| 4e01b467 | 748 | crit_exit(); |
| 984263bc MD |
749 | } |
| 750 | ||
| 6ed427ca | 751 | static int |
| 984263bc MD |
752 | ukbd_interrupt(keyboard_t *kbd, void *arg) |
| 753 | { | |
| 754 | usbd_status status = (usbd_status)arg; | |
| 1550dfd9 MD |
755 | ukbd_state_t *state; |
| 756 | struct ukbd_data *ud; | |
| 984263bc MD |
757 | struct timeval tv; |
| 758 | u_long now; | |
| 759 | int mod, omod; | |
| 760 | int key, c; | |
| 761 | int i, j; | |
| 762 | ||
| 984263bc MD |
763 | DPRINTFN(5, ("ukbd_intr: status=%d\n", status)); |
| 764 | if (status == USBD_CANCELLED) | |
| 765 | return 0; | |
| 766 | ||
| 1550dfd9 MD |
767 | state = (ukbd_state_t *)kbd->kb_data; |
| 768 | ud = &state->ks_ndata; | |
| 769 | ||
| 984263bc MD |
770 | if (status != USBD_NORMAL_COMPLETION) { |
| 771 | DPRINTF(("ukbd_intr: status=%d\n", status)); | |
| 1550dfd9 MD |
772 | if (status == USBD_STALLED) |
| 773 | usbd_clear_endpoint_stall_async(state->ks_intrpipe); | |
| 984263bc MD |
774 | return 0; |
| 775 | } | |
| 776 | ||
| 777 | if (ud->keycode[0] == KEY_ERROR) | |
| 778 | return 0; /* ignore */ | |
| 779 | ||
| 780 | getmicrouptime(&tv); | |
| 781 | now = (u_long)tv.tv_sec*1000 + (u_long)tv.tv_usec/1000; | |
| 782 | ||
| 1550dfd9 MD |
783 | #define ADDKEY1(c) \ |
| 784 | if (state->ks_inputs < INPUTBUFSIZE) { \ | |
| 785 | state->ks_input[state->ks_inputtail] = (c); \ | |
| 786 | ++state->ks_inputs; \ | |
| 787 | state->ks_inputtail = (state->ks_inputtail + 1)%INPUTBUFSIZE; \ | |
| 788 | } | |
| 789 | ||
| 984263bc MD |
790 | mod = ud->modifiers; |
| 791 | omod = state->ks_odata.modifiers; | |
| 792 | if (mod != omod) { | |
| 793 | for (i = 0; i < NMOD; i++) | |
| 1550dfd9 | 794 | if (( mod & ukbd_mods[i].mask) != |
| 984263bc | 795 | (omod & ukbd_mods[i].mask)) |
| 1550dfd9 MD |
796 | ADDKEY1(ukbd_mods[i].key | |
| 797 | (mod & ukbd_mods[i].mask | |
| 984263bc MD |
798 | ? KEY_PRESS : KEY_RELEASE)); |
| 799 | } | |
| 800 | ||
| 801 | /* Check for released keys. */ | |
| 802 | for (i = 0; i < NKEYCODE; i++) { | |
| 803 | key = state->ks_odata.keycode[i]; | |
| 804 | if (key == 0) | |
| 32930970 | 805 | continue; |
| 984263bc MD |
806 | for (j = 0; j < NKEYCODE; j++) { |
| 807 | if (ud->keycode[j] == 0) | |
| 32930970 | 808 | continue; |
| 984263bc MD |
809 | if (key == ud->keycode[j]) |
| 810 | goto rfound; | |
| 811 | } | |
| 812 | ADDKEY1(key | KEY_RELEASE); | |
| 813 | rfound: | |
| 814 | ; | |
| 815 | } | |
| 1550dfd9 | 816 | |
| 984263bc MD |
817 | /* Check for pressed keys. */ |
| 818 | for (i = 0; i < NKEYCODE; i++) { | |
| 819 | key = ud->keycode[i]; | |
| 820 | if (key == 0) | |
| 32930970 | 821 | continue; |
| 984263bc MD |
822 | state->ks_ntime[i] = now + kbd->kb_delay1; |
| 823 | for (j = 0; j < NKEYCODE; j++) { | |
| 824 | if (state->ks_odata.keycode[j] == 0) | |
| 32930970 | 825 | continue; |
| 984263bc MD |
826 | if (key == state->ks_odata.keycode[j]) { |
| 827 | state->ks_ntime[i] = state->ks_otime[j]; | |
| 828 | if (state->ks_otime[j] > now) | |
| 829 | goto pfound; | |
| 830 | state->ks_ntime[i] = now + kbd->kb_delay2; | |
| 831 | break; | |
| 832 | } | |
| 833 | } | |
| 834 | ADDKEY1(key | KEY_PRESS); | |
| 835 | pfound: | |
| 836 | ; | |
| 837 | } | |
| 838 | ||
| 839 | state->ks_odata = *ud; | |
| 840 | bcopy(state->ks_ntime, state->ks_otime, sizeof(state->ks_ntime)); | |
| 841 | if (state->ks_inputs <= 0) | |
| 842 | return 0; | |
| 843 | ||
| 844 | #ifdef USB_DEBUG | |
| 845 | for (i = state->ks_inputhead, j = 0; j < state->ks_inputs; ++j, | |
| 846 | i = (i + 1)%INPUTBUFSIZE) { | |
| 847 | c = state->ks_input[i]; | |
| 848 | DPRINTF(("0x%x (%d) %s\n", c, c, | |
| 849 | (c & KEY_RELEASE) ? "released":"pressed")); | |
| 850 | } | |
| 851 | if (ud->modifiers) | |
| 852 | DPRINTF(("mod:0x%04x ", ud->modifiers)); | |
| 853 | for (i = 0; i < NKEYCODE; i++) { | |
| 854 | if (ud->keycode[i]) | |
| 855 | DPRINTF(("%d ", ud->keycode[i])); | |
| 856 | } | |
| 857 | DPRINTF(("\n")); | |
| 858 | #endif /* USB_DEBUG */ | |
| 859 | ||
| 860 | if (state->ks_polling) | |
| 861 | return 0; | |
| 862 | ||
| 863 | if (KBD_IS_ACTIVE(kbd) && KBD_IS_BUSY(kbd)) { | |
| 864 | /* let the callback function to process the input */ | |
| 865 | (*kbd->kb_callback.kc_func)(kbd, KBDIO_KEYINPUT, | |
| 866 | kbd->kb_callback.kc_arg); | |
| 867 | } else { | |
| 868 | /* read and discard the input; no one is waiting for it */ | |
| 869 | do { | |
| 870 | c = ukbd_read_char(kbd, FALSE); | |
| 871 | } while (c != NOKEY); | |
| 872 | } | |
| 873 | ||
| 874 | return 0; | |
| 875 | } | |
| 876 | ||
| 6ed427ca | 877 | static int |
| 984263bc MD |
878 | ukbd_getc(ukbd_state_t *state) |
| 879 | { | |
| 880 | int c; | |
| 984263bc MD |
881 | |
| 882 | if (state->ks_polling) { | |
| 883 | DPRINTFN(1,("ukbd_getc: polling\n")); | |
| 4e01b467 | 884 | crit_enter(); |
| 984263bc MD |
885 | while (state->ks_inputs <= 0) |
| 886 | usbd_dopoll(state->ks_iface); | |
| 4e01b467 | 887 | crit_exit(); |
| 984263bc | 888 | } |
| 4e01b467 | 889 | crit_enter(); |
| 984263bc MD |
890 | if (state->ks_inputs <= 0) { |
| 891 | c = -1; | |
| 892 | } else { | |
| 893 | c = state->ks_input[state->ks_inputhead]; | |
| 894 | --state->ks_inputs; | |
| 895 | state->ks_inputhead = (state->ks_inputhead + 1)%INPUTBUFSIZE; | |
| 896 | } | |
| 4e01b467 | 897 | crit_exit(); |
| 984263bc MD |
898 | return c; |
| 899 | } | |
| 900 | ||
| 901 | /* test the interface to the device */ | |
| 6ed427ca | 902 | static int |
| 984263bc MD |
903 | ukbd_test_if(keyboard_t *kbd) |
| 904 | { | |
| 905 | return 0; | |
| 906 | } | |
| 907 | ||
| 1550dfd9 | 908 | /* |
| 984263bc MD |
909 | * Enable the access to the device; until this function is called, |
| 910 | * the client cannot read from the keyboard. | |
| 911 | */ | |
| 6ed427ca | 912 | static int |
| 984263bc MD |
913 | ukbd_enable(keyboard_t *kbd) |
| 914 | { | |
| 4e01b467 | 915 | crit_enter(); |
| 984263bc | 916 | KBD_ACTIVATE(kbd); |
| 4e01b467 | 917 | crit_exit(); |
| 984263bc MD |
918 | return 0; |
| 919 | } | |
| 920 | ||
| 921 | /* disallow the access to the device */ | |
| 6ed427ca | 922 | static int |
| 984263bc MD |
923 | ukbd_disable(keyboard_t *kbd) |
| 924 | { | |
| 4e01b467 | 925 | crit_enter(); |
| 984263bc | 926 | KBD_DEACTIVATE(kbd); |
| 4e01b467 | 927 | crit_exit(); |
| 984263bc MD |
928 | return 0; |
| 929 | } | |
| 930 | ||
| 931 | /* read one byte from the keyboard if it's allowed */ | |
| 6ed427ca | 932 | static int |
| 984263bc MD |
933 | ukbd_read(keyboard_t *kbd, int wait) |
| 934 | { | |
| 935 | ukbd_state_t *state; | |
| 936 | int usbcode; | |
| 937 | #ifdef UKBD_EMULATE_ATSCANCODE | |
| 938 | int keycode; | |
| 939 | int scancode; | |
| 940 | #endif | |
| 941 | ||
| 942 | state = (ukbd_state_t *)kbd->kb_data; | |
| 943 | #ifdef UKBD_EMULATE_ATSCANCODE | |
| 944 | if (state->ks_buffered_char[0]) { | |
| 945 | scancode = state->ks_buffered_char[0]; | |
| 946 | if (scancode & SCAN_PREFIX) { | |
| 947 | state->ks_buffered_char[0] = scancode & ~SCAN_PREFIX; | |
| 948 | return ((scancode & SCAN_PREFIX_E0) ? 0xe0 : 0xe1); | |
| 949 | } else { | |
| 950 | state->ks_buffered_char[0] = state->ks_buffered_char[1]; | |
| 951 | state->ks_buffered_char[1] = 0; | |
| 952 | return scancode; | |
| 953 | } | |
| 954 | } | |
| 955 | #endif /* UKBD_EMULATE_ATSCANCODE */ | |
| 956 | ||
| 957 | /* XXX */ | |
| 958 | usbcode = ukbd_getc(state); | |
| 0abf15af | 959 | if (!KBD_IS_ACTIVE(kbd) || !KBD_HAS_DEVICE(kbd) || (usbcode == -1)) |
| 984263bc MD |
960 | return -1; |
| 961 | ++kbd->kb_count; | |
| 962 | #ifdef UKBD_EMULATE_ATSCANCODE | |
| 963 | keycode = ukbd_trtab[KEY_INDEX(usbcode)]; | |
| 964 | if (keycode == NN) | |
| 965 | return -1; | |
| 966 | ||
| 967 | scancode = keycode2scancode(keycode, state->ks_ndata.modifiers, | |
| 968 | usbcode & KEY_RELEASE); | |
| 969 | if (scancode & SCAN_PREFIX) { | |
| 970 | if (scancode & SCAN_PREFIX_CTL) { | |
| 1550dfd9 | 971 | state->ks_buffered_char[0] = |
| 984263bc MD |
972 | 0x1d | (scancode & SCAN_RELEASE); /* Ctrl */ |
| 973 | state->ks_buffered_char[1] = scancode & ~SCAN_PREFIX; | |
| 974 | } else if (scancode & SCAN_PREFIX_SHIFT) { | |
| 1550dfd9 | 975 | state->ks_buffered_char[0] = |
| 984263bc | 976 | 0x2a | (scancode & SCAN_RELEASE); /* Shift */ |
| 1550dfd9 | 977 | state->ks_buffered_char[1] = |
| 984263bc MD |
978 | scancode & ~SCAN_PREFIX_SHIFT; |
| 979 | } else { | |
| 980 | state->ks_buffered_char[0] = scancode & ~SCAN_PREFIX; | |
| 981 | state->ks_buffered_char[1] = 0; | |
| 982 | } | |
| 983 | return ((scancode & SCAN_PREFIX_E0) ? 0xe0 : 0xe1); | |
| 984 | } | |
| 985 | return scancode; | |
| 986 | #else /* !UKBD_EMULATE_ATSCANCODE */ | |
| 987 | return usbcode; | |
| 988 | #endif /* UKBD_EMULATE_ATSCANCODE */ | |
| 989 | } | |
| 990 | ||
| 991 | /* check if data is waiting */ | |
| 6ed427ca | 992 | static int |
| 984263bc MD |
993 | ukbd_check(keyboard_t *kbd) |
| 994 | { | |
| 0abf15af | 995 | if (!KBD_IS_ACTIVE(kbd) || !KBD_HAS_DEVICE(kbd)) |
| 984263bc MD |
996 | return FALSE; |
| 997 | #ifdef UKBD_EMULATE_ATSCANCODE | |
| 998 | if (((ukbd_state_t *)kbd->kb_data)->ks_buffered_char[0]) | |
| 999 | return TRUE; | |
| 1000 | #endif | |
| 1001 | if (((ukbd_state_t *)kbd->kb_data)->ks_inputs > 0) | |
| 1002 | return TRUE; | |
| 1003 | return FALSE; | |
| 1004 | } | |
| 1005 | ||
| 1006 | /* read char from the keyboard */ | |
| 6ed427ca | 1007 | static u_int |
| 984263bc MD |
1008 | ukbd_read_char(keyboard_t *kbd, int wait) |
| 1009 | { | |
| 1010 | ukbd_state_t *state; | |
| 1011 | u_int action; | |
| 1012 | int usbcode; | |
| 1013 | int keycode; | |
| 1014 | #ifdef UKBD_EMULATE_ATSCANCODE | |
| 1015 | int scancode; | |
| 1016 | #endif | |
| 1017 | ||
| 1018 | state = (ukbd_state_t *)kbd->kb_data; | |
| 1019 | next_code: | |
| 1020 | /* do we have a composed char to return? */ | |
| 1021 | if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) { | |
| 1022 | action = state->ks_composed_char; | |
| 1023 | state->ks_composed_char = 0; | |
| 1024 | if (action > UCHAR_MAX) | |
| 1025 | return ERRKEY; | |
| 1026 | return action; | |
| 1027 | } | |
| 1028 | ||
| 1029 | #ifdef UKBD_EMULATE_ATSCANCODE | |
| 1030 | /* do we have a pending raw scan code? */ | |
| 1031 | if (state->ks_mode == K_RAW) { | |
| 1032 | if (state->ks_buffered_char[0]) { | |
| 1033 | scancode = state->ks_buffered_char[0]; | |
| 1034 | if (scancode & SCAN_PREFIX) { | |
| 1035 | state->ks_buffered_char[0] = | |
| 1036 | scancode & ~SCAN_PREFIX; | |
| 1037 | return ((scancode & SCAN_PREFIX_E0) ? 0xe0 : 0xe1); | |
| 1038 | } else { | |
| 1039 | state->ks_buffered_char[0] = | |
| 1040 | state->ks_buffered_char[1]; | |
| 1041 | state->ks_buffered_char[1] = 0; | |
| 1042 | return scancode; | |
| 1043 | } | |
| 1044 | } | |
| 1045 | } | |
| 1046 | #endif /* UKBD_EMULATE_ATSCANCODE */ | |
| 1047 | ||
| 1048 | /* see if there is something in the keyboard port */ | |
| 1049 | /* XXX */ | |
| 1050 | usbcode = ukbd_getc(state); | |
| 1051 | if (usbcode == -1) | |
| 1052 | return NOKEY; | |
| 1053 | ++kbd->kb_count; | |
| 1054 | ||
| 1055 | #ifdef UKBD_EMULATE_ATSCANCODE | |
| 1056 | /* USB key index -> key code -> AT scan code */ | |
| 1057 | keycode = ukbd_trtab[KEY_INDEX(usbcode)]; | |
| 1058 | if (keycode == NN) | |
| 1059 | return NOKEY; | |
| 1060 | ||
| 1061 | /* return an AT scan code for the K_RAW mode */ | |
| 1062 | if (state->ks_mode == K_RAW) { | |
| 1063 | scancode = keycode2scancode(keycode, state->ks_ndata.modifiers, | |
| 1064 | usbcode & KEY_RELEASE); | |
| 1065 | if (scancode & SCAN_PREFIX) { | |
| 1066 | if (scancode & SCAN_PREFIX_CTL) { | |
| 1550dfd9 | 1067 | state->ks_buffered_char[0] = |
| 984263bc MD |
1068 | 0x1d | (scancode & SCAN_RELEASE); |
| 1069 | state->ks_buffered_char[1] = | |
| 1070 | scancode & ~SCAN_PREFIX; | |
| 1071 | } else if (scancode & SCAN_PREFIX_SHIFT) { | |
| 1550dfd9 | 1072 | state->ks_buffered_char[0] = |
| 984263bc MD |
1073 | 0x2a | (scancode & SCAN_RELEASE); |
| 1074 | state->ks_buffered_char[1] = | |
| 1075 | scancode & ~SCAN_PREFIX_SHIFT; | |
| 1076 | } else { | |
| 1077 | state->ks_buffered_char[0] = | |
| 1078 | scancode & ~SCAN_PREFIX; | |
| 1079 | state->ks_buffered_char[1] = 0; | |
| 1080 | } | |
| 1081 | return ((scancode & SCAN_PREFIX_E0) ? 0xe0 : 0xe1); | |
| 1082 | } | |
| 1083 | return scancode; | |
| 1084 | } | |
| 1085 | #else /* !UKBD_EMULATE_ATSCANCODE */ | |
| 1086 | /* return the byte as is for the K_RAW mode */ | |
| 1087 | if (state->ks_mode == K_RAW) | |
| 1088 | return usbcode; | |
| 1089 | ||
| 1090 | /* USB key index -> key code */ | |
| 1091 | keycode = ukbd_trtab[KEY_INDEX(usbcode)]; | |
| 1092 | if (keycode == NN) | |
| 1093 | return NOKEY; | |
| 1094 | #endif /* UKBD_EMULATE_ATSCANCODE */ | |
| 1095 | ||
| 1096 | switch (keycode) { | |
| 1097 | case 0x38: /* left alt (compose key) */ | |
| 1098 | if (usbcode & KEY_RELEASE) { | |
| 1099 | if (state->ks_flags & COMPOSE) { | |
| 1100 | state->ks_flags &= ~COMPOSE; | |
| 1101 | if (state->ks_composed_char > UCHAR_MAX) | |
| 1102 | state->ks_composed_char = 0; | |
| 1103 | } | |
| 1104 | } else { | |
| 1105 | if (!(state->ks_flags & COMPOSE)) { | |
| 1106 | state->ks_flags |= COMPOSE; | |
| 1107 | state->ks_composed_char = 0; | |
| 1108 | } | |
| 1109 | } | |
| 1110 | break; | |
| 1111 | /* XXX: I don't like these... */ | |
| 1112 | case 0x5c: /* print screen */ | |
| 1113 | if (state->ks_flags & ALTS) | |
| 1114 | keycode = 0x54; /* sysrq */ | |
| 1115 | break; | |
| 1116 | case 0x68: /* pause/break */ | |
| 1117 | if (state->ks_flags & CTLS) | |
| 1118 | keycode = 0x6c; /* break */ | |
| 1119 | break; | |
| 1120 | } | |
| 1121 | ||
| 1122 | /* return the key code in the K_CODE mode */ | |
| 1123 | if (usbcode & KEY_RELEASE) | |
| 1124 | keycode |= SCAN_RELEASE; | |
| 1125 | if (state->ks_mode == K_CODE) | |
| 1126 | return keycode; | |
| 1127 | ||
| 1128 | /* compose a character code */ | |
| 1129 | if (state->ks_flags & COMPOSE) { | |
| 1130 | switch (keycode) { | |
| 1131 | /* key pressed, process it */ | |
| 1132 | case 0x47: case 0x48: case 0x49: /* keypad 7,8,9 */ | |
| 1133 | state->ks_composed_char *= 10; | |
| 1134 | state->ks_composed_char += keycode - 0x40; | |
| 1135 | if (state->ks_composed_char > UCHAR_MAX) | |
| 1136 | return ERRKEY; | |
| 1137 | goto next_code; | |
| 1138 | case 0x4B: case 0x4C: case 0x4D: /* keypad 4,5,6 */ | |
| 1139 | state->ks_composed_char *= 10; | |
| 1140 | state->ks_composed_char += keycode - 0x47; | |
| 1141 | if (state->ks_composed_char > UCHAR_MAX) | |
| 1142 | return ERRKEY; | |
| 1143 | goto next_code; | |
| 1144 | case 0x4F: case 0x50: case 0x51: /* keypad 1,2,3 */ | |
| 1145 | state->ks_composed_char *= 10; | |
| 1146 | state->ks_composed_char += keycode - 0x4E; | |
| 1147 | if (state->ks_composed_char > UCHAR_MAX) | |
| 1148 | return ERRKEY; | |
| 1149 | goto next_code; | |
| 1150 | case 0x52: /* keypad 0 */ | |
| 1151 | state->ks_composed_char *= 10; | |
| 1152 | if (state->ks_composed_char > UCHAR_MAX) | |
| 1153 | return ERRKEY; | |
| 1154 | goto next_code; | |
| 1155 | ||
| 1156 | /* key released, no interest here */ | |
| 1157 | case SCAN_RELEASE | 0x47: | |
| 1158 | case SCAN_RELEASE | 0x48: | |
| 1159 | case SCAN_RELEASE | 0x49: /* keypad 7,8,9 */ | |
| 1160 | case SCAN_RELEASE | 0x4B: | |
| 1161 | case SCAN_RELEASE | 0x4C: | |
| 1162 | case SCAN_RELEASE | 0x4D: /* keypad 4,5,6 */ | |
| 1163 | case SCAN_RELEASE | 0x4F: | |
| 1164 | case SCAN_RELEASE | 0x50: | |
| 1165 | case SCAN_RELEASE | 0x51: /* keypad 1,2,3 */ | |
| 1166 | case SCAN_RELEASE | 0x52: /* keypad 0 */ | |
| 1167 | goto next_code; | |
| 1168 | ||
| 1169 | case 0x38: /* left alt key */ | |
| 1170 | break; | |
| 1171 | ||
| 1172 | default: | |
| 1173 | if (state->ks_composed_char > 0) { | |
| 1174 | state->ks_flags &= ~COMPOSE; | |
| 1175 | state->ks_composed_char = 0; | |
| 1176 | return ERRKEY; | |
| 1177 | } | |
| 1178 | break; | |
| 1179 | } | |
| 1180 | } | |
| 1181 | ||
| 1182 | /* keycode to key action */ | |
| 1183 | action = genkbd_keyaction(kbd, SCAN_CHAR(keycode), | |
| 1184 | keycode & SCAN_RELEASE, &state->ks_state, | |
| 1185 | &state->ks_accents); | |
| 1186 | if (action == NOKEY) | |
| 1187 | goto next_code; | |
| 1188 | else | |
| 1189 | return action; | |
| 1190 | } | |
| 1191 | ||
| 1192 | /* check if char is waiting */ | |
| 6ed427ca | 1193 | static int |
| 984263bc MD |
1194 | ukbd_check_char(keyboard_t *kbd) |
| 1195 | { | |
| 1196 | ukbd_state_t *state; | |
| 1197 | ||
| 0abf15af | 1198 | if (!KBD_IS_ACTIVE(kbd) || !KBD_HAS_DEVICE(kbd)) |
| 984263bc MD |
1199 | return FALSE; |
| 1200 | state = (ukbd_state_t *)kbd->kb_data; | |
| 1201 | if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) | |
| 1202 | return TRUE; | |
| 8ddb2073 | 1203 | return (ukbd_check(kbd)); |
| 984263bc MD |
1204 | } |
| 1205 | ||
| 1206 | /* some useful control functions */ | |
| 6ed427ca | 1207 | static int |
| 984263bc MD |
1208 | ukbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg) |
| 1209 | { | |
| 1210 | /* trasnlate LED_XXX bits into the device specific bits */ | |
| 1211 | static u_char ledmap[8] = { | |
| 1212 | 0, 2, 1, 3, 4, 6, 5, 7, | |
| 1213 | }; | |
| 1214 | ukbd_state_t *state = kbd->kb_data; | |
| 984263bc MD |
1215 | int i; |
| 1216 | ||
| 4e01b467 | 1217 | crit_enter(); |
| 984263bc | 1218 | switch (cmd) { |
| 984263bc MD |
1219 | case KDGKBMODE: /* get keyboard mode */ |
| 1220 | *(int *)arg = state->ks_mode; | |
| 1221 | break; | |
| 1222 | case KDSKBMODE: /* set keyboard mode */ | |
| 1223 | switch (*(int *)arg) { | |
| 1224 | case K_XLATE: | |
| 1225 | if (state->ks_mode != K_XLATE) { | |
| 1226 | /* make lock key state and LED state match */ | |
| 1227 | state->ks_state &= ~LOCK_MASK; | |
| 1228 | state->ks_state |= KBD_LED_VAL(kbd); | |
| 1229 | } | |
| 1550dfd9 | 1230 | /* FALLTHROUGH */ |
| 984263bc MD |
1231 | case K_RAW: |
| 1232 | case K_CODE: | |
| 1233 | if (state->ks_mode != *(int *)arg) { | |
| 1234 | ukbd_clear_state(kbd); | |
| 1235 | state->ks_mode = *(int *)arg; | |
| fcd74d1b | 1236 | kbd->kb_savemode = state->ks_mode; |
| 984263bc MD |
1237 | } |
| 1238 | break; | |
| 1239 | default: | |
| 4e01b467 | 1240 | crit_exit(); |
| 984263bc MD |
1241 | return EINVAL; |
| 1242 | } | |
| 1243 | break; | |
| 1244 | ||
| 1245 | case KDGETLED: /* get keyboard LED */ | |
| 1246 | *(int *)arg = KBD_LED_VAL(kbd); | |
| 1247 | break; | |
| 1248 | case KDSETLED: /* set keyboard LED */ | |
| 1249 | /* NOTE: lock key state in ks_state won't be changed */ | |
| 1250 | if (*(int *)arg & ~LOCK_MASK) { | |
| 4e01b467 | 1251 | crit_exit(); |
| 984263bc MD |
1252 | return EINVAL; |
| 1253 | } | |
| 1254 | i = *(int *)arg; | |
| 1255 | /* replace CAPS LED with ALTGR LED for ALTGR keyboards */ | |
| 1256 | if (kbd->kb_keymap->n_keys > ALTGR_OFFSET) { | |
| 1257 | if (i & ALKED) | |
| 1258 | i |= CLKED; | |
| 1259 | else | |
| 1260 | i &= ~CLKED; | |
| 1261 | } | |
| 1262 | if (KBD_HAS_DEVICE(kbd)) { | |
| 1263 | set_leds(state, ledmap[i & LED_MASK]); | |
| 1264 | /* XXX: error check? */ | |
| 1265 | } | |
| 1266 | KBD_LED_VAL(kbd) = *(int *)arg; | |
| 1267 | break; | |
| 1268 | ||
| 1269 | case KDGKBSTATE: /* get lock key state */ | |
| 1270 | *(int *)arg = state->ks_state & LOCK_MASK; | |
| 1271 | break; | |
| 1272 | case KDSKBSTATE: /* set lock key state */ | |
| 1273 | if (*(int *)arg & ~LOCK_MASK) { | |
| 4e01b467 | 1274 | crit_exit(); |
| 984263bc MD |
1275 | return EINVAL; |
| 1276 | } | |
| 1277 | state->ks_state &= ~LOCK_MASK; | |
| 1278 | state->ks_state |= *(int *)arg; | |
| 4e01b467 | 1279 | crit_exit(); |
| 984263bc MD |
1280 | /* set LEDs and quit */ |
| 1281 | return ukbd_ioctl(kbd, KDSETLED, arg); | |
| 1282 | ||
| 1283 | case KDSETREPEAT: /* set keyboard repeat rate (new interface) */ | |
| 4e01b467 | 1284 | crit_exit(); |
| 984263bc MD |
1285 | if (!KBD_HAS_DEVICE(kbd)) |
| 1286 | return 0; | |
| 1287 | if (((int *)arg)[1] < 0) | |
| 1288 | return EINVAL; | |
| 1289 | if (((int *)arg)[0] < 0) | |
| 1290 | return EINVAL; | |
| 1291 | else if (((int *)arg)[0] == 0) /* fastest possible value */ | |
| 1292 | kbd->kb_delay1 = 200; | |
| 1293 | else | |
| 1294 | kbd->kb_delay1 = ((int *)arg)[0]; | |
| 1295 | kbd->kb_delay2 = ((int *)arg)[1]; | |
| 1296 | return 0; | |
| 1297 | ||
| 1298 | case KDSETRAD: /* set keyboard repeat rate (old interface) */ | |
| 4e01b467 | 1299 | crit_exit(); |
| 984263bc MD |
1300 | return set_typematic(kbd, *(int *)arg); |
| 1301 | ||
| 1302 | case PIO_KEYMAP: /* set keyboard translation table */ | |
| 1303 | case PIO_KEYMAPENT: /* set keyboard translation table entry */ | |
| 1304 | case PIO_DEADKEYMAP: /* set accent key translation table */ | |
| 1305 | state->ks_accents = 0; | |
| 1550dfd9 | 1306 | /* FALLTHROUGH */ |
| 984263bc | 1307 | default: |
| 4e01b467 | 1308 | crit_exit(); |
| 984263bc MD |
1309 | return genkbd_commonioctl(kbd, cmd, arg); |
| 1310 | ||
| 1311 | #ifdef USB_DEBUG | |
| 1312 | case USB_SETDEBUG: | |
| 1313 | ukbddebug = *(int *)arg; | |
| 1314 | break; | |
| 1315 | #endif | |
| 1316 | } | |
| 1317 | ||
| 4e01b467 | 1318 | crit_exit(); |
| 984263bc MD |
1319 | return 0; |
| 1320 | } | |
| 1321 | ||
| 1322 | /* lock the access to the keyboard */ | |
| 6ed427ca | 1323 | static int |
| 984263bc MD |
1324 | ukbd_lock(keyboard_t *kbd, int lock) |
| 1325 | { | |
| 1326 | /* XXX ? */ | |
| 1327 | return TRUE; | |
| 1328 | } | |
| 1329 | ||
| 1330 | /* clear the internal state of the keyboard */ | |
| 6ed427ca | 1331 | static void |
| 984263bc MD |
1332 | ukbd_clear_state(keyboard_t *kbd) |
| 1333 | { | |
| 1334 | ukbd_state_t *state; | |
| 1335 | ||
| 1336 | state = (ukbd_state_t *)kbd->kb_data; | |
| 1337 | state->ks_flags = 0; | |
| 1338 | state->ks_polling = 0; | |
| 1339 | state->ks_state &= LOCK_MASK; /* preserve locking key state */ | |
| 1340 | state->ks_accents = 0; | |
| 1341 | state->ks_composed_char = 0; | |
| 1342 | #ifdef UKBD_EMULATE_ATSCANCODE | |
| 1343 | state->ks_buffered_char[0] = 0; | |
| 1344 | state->ks_buffered_char[1] = 0; | |
| 1345 | #endif | |
| 1346 | bzero(&state->ks_ndata, sizeof(state->ks_ndata)); | |
| 1347 | bzero(&state->ks_odata, sizeof(state->ks_odata)); | |
| 1348 | bzero(&state->ks_ntime, sizeof(state->ks_ntime)); | |
| 1349 | bzero(&state->ks_otime, sizeof(state->ks_otime)); | |
| 1350 | } | |
| 1351 | ||
| 1352 | /* save the internal state */ | |
| 6ed427ca | 1353 | static int |
| 984263bc MD |
1354 | ukbd_get_state(keyboard_t *kbd, void *buf, size_t len) |
| 1355 | { | |
| 1356 | if (len == 0) | |
| 1357 | return sizeof(ukbd_state_t); | |
| 1358 | if (len < sizeof(ukbd_state_t)) | |
| 1359 | return -1; | |
| 1360 | bcopy(kbd->kb_data, buf, sizeof(ukbd_state_t)); | |
| 1361 | return 0; | |
| 1362 | } | |
| 1363 | ||
| 1364 | /* set the internal state */ | |
| 6ed427ca | 1365 | static int |
| 984263bc MD |
1366 | ukbd_set_state(keyboard_t *kbd, void *buf, size_t len) |
| 1367 | { | |
| 1368 | if (len < sizeof(ukbd_state_t)) | |
| 1369 | return ENOMEM; | |
| 1370 | bcopy(buf, kbd->kb_data, sizeof(ukbd_state_t)); | |
| 1371 | return 0; | |
| 1372 | } | |
| 1373 | ||
| 6ed427ca | 1374 | static int |
| 984263bc MD |
1375 | ukbd_poll(keyboard_t *kbd, int on) |
| 1376 | { | |
| 1377 | ukbd_state_t *state; | |
| 1550dfd9 | 1378 | usbd_device_handle dev; |
| 984263bc MD |
1379 | |
| 1380 | state = (ukbd_state_t *)kbd->kb_data; | |
| 1550dfd9 | 1381 | usbd_interface2device_handle(state->ks_iface, &dev); |
| 984263bc | 1382 | |
| 4e01b467 | 1383 | crit_enter(); |
| 984263bc MD |
1384 | if (on) { |
| 1385 | if (state->ks_polling == 0) | |
| 1550dfd9 | 1386 | usbd_set_polling(dev, on); |
| 984263bc MD |
1387 | ++state->ks_polling; |
| 1388 | } else { | |
| 1389 | --state->ks_polling; | |
| 1390 | if (state->ks_polling == 0) | |
| 1550dfd9 | 1391 | usbd_set_polling(dev, on); |
| 984263bc | 1392 | } |
| 4e01b467 | 1393 | crit_exit(); |
| 984263bc MD |
1394 | return 0; |
| 1395 | } | |
| 1396 | ||
| 1397 | /* local functions */ | |
| 1398 | ||
| 6ed427ca | 1399 | static int |
| 984263bc MD |
1400 | probe_keyboard(struct usb_attach_arg *uaa, int flags) |
| 1401 | { | |
| 1402 | usb_interface_descriptor_t *id; | |
| 1550dfd9 | 1403 | |
| 984263bc MD |
1404 | if (!uaa->iface) /* we attach to ifaces only */ |
| 1405 | return EINVAL; | |
| 1406 | ||
| 1407 | /* Check that this is a keyboard that speaks the boot protocol. */ | |
| 1408 | id = usbd_get_interface_descriptor(uaa->iface); | |
| 1409 | if (id | |
| 1410 | && id->bInterfaceClass == UICLASS_HID | |
| 1411 | && id->bInterfaceSubClass == UISUBCLASS_BOOT | |
| 1412 | && id->bInterfaceProtocol == UPROTO_BOOT_KEYBOARD) | |
| 1413 | return 0; /* found it */ | |
| 1414 | ||
| 1415 | return EINVAL; | |
| 1416 | } | |
| 1417 | ||
| 6ed427ca | 1418 | static int |
| 984263bc MD |
1419 | init_keyboard(ukbd_state_t *state, int *type, int flags) |
| 1420 | { | |
| 1421 | usb_endpoint_descriptor_t *ed; | |
| 1422 | usbd_status err; | |
| 1550dfd9 | 1423 | |
| 984263bc MD |
1424 | *type = KB_OTHER; |
| 1425 | ||
| 1426 | state->ks_ifstate |= DISCONNECTED; | |
| 1427 | ||
| 1428 | ed = usbd_interface2endpoint_descriptor(state->ks_iface, 0); | |
| 1429 | if (!ed) { | |
| e3869ec7 | 1430 | kprintf("ukbd: could not read endpoint descriptor\n"); |
| 984263bc MD |
1431 | return EIO; |
| 1432 | } | |
| 1433 | ||
| 1434 | DPRINTFN(10,("ukbd:init_keyboard: \ | |
| 1435 | bLength=%d bDescriptorType=%d bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d bInterval=%d\n", | |
| 1436 | ed->bLength, ed->bDescriptorType, | |
| 1437 | UE_GET_ADDR(ed->bEndpointAddress), | |
| 1438 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN ? "in":"out", | |
| 1439 | UE_GET_XFERTYPE(ed->bmAttributes), | |
| 1440 | UGETW(ed->wMaxPacketSize), ed->bInterval)); | |
| 1441 | ||
| 1442 | if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_IN || | |
| 1443 | UE_GET_XFERTYPE(ed->bmAttributes) != UE_INTERRUPT) { | |
| e3869ec7 | 1444 | kprintf("ukbd: unexpected endpoint\n"); |
| 984263bc MD |
1445 | return EINVAL; |
| 1446 | } | |
| 1447 | ||
| 1448 | if ((usbd_get_quirks(state->ks_uaa->device)->uq_flags & UQ_NO_SET_PROTO) == 0) { | |
| 1449 | err = usbd_set_protocol(state->ks_iface, 0); | |
| 1450 | DPRINTFN(5, ("ukbd:init_keyboard: protocol set\n")); | |
| 1451 | if (err) { | |
| e3869ec7 | 1452 | kprintf("ukbd: set protocol failed\n"); |
| 984263bc MD |
1453 | return EIO; |
| 1454 | } | |
| 1455 | } | |
| 1456 | /* Ignore if SETIDLE fails since it is not crucial. */ | |
| 1457 | usbd_set_idle(state->ks_iface, 0, 0); | |
| 1458 | ||
| 1459 | state->ks_ep_addr = ed->bEndpointAddress; | |
| 1460 | state->ks_ifstate &= ~DISCONNECTED; | |
| 1461 | ||
| 1462 | return 0; | |
| 1463 | } | |
| 1464 | ||
| 6ed427ca | 1465 | static void |
| 984263bc MD |
1466 | set_leds(ukbd_state_t *state, int leds) |
| 1467 | { | |
| 1468 | u_int8_t res = leds; | |
| 1469 | ||
| 1470 | DPRINTF(("ukbd:set_leds: state=%p leds=%d\n", state, leds)); | |
| 1471 | ||
| 1472 | usbd_set_report_async(state->ks_iface, UHID_OUTPUT_REPORT, 0, &res, 1); | |
| 1473 | } | |
| 1474 | ||
| 6ed427ca | 1475 | static int |
| 984263bc MD |
1476 | set_typematic(keyboard_t *kbd, int code) |
| 1477 | { | |
| 1478 | static int delays[] = { 250, 500, 750, 1000 }; | |
| 1479 | static int rates[] = { 34, 38, 42, 46, 50, 55, 59, 63, | |
| 1480 | 68, 76, 84, 92, 100, 110, 118, 126, | |
| 1481 | 136, 152, 168, 184, 200, 220, 236, 252, | |
| 1482 | 272, 304, 336, 368, 400, 440, 472, 504 }; | |
| 1483 | ||
| 1484 | if (code & ~0x7f) | |
| 1485 | return EINVAL; | |
| 1486 | kbd->kb_delay1 = delays[(code >> 5) & 3]; | |
| 1487 | kbd->kb_delay2 = rates[code & 0x1f]; | |
| 1488 | return 0; | |
| 1489 | } | |
| 1490 | ||
| 1491 | #ifdef UKBD_EMULATE_ATSCANCODE | |
| 6ed427ca | 1492 | static int |
| 984263bc MD |
1493 | keycode2scancode(int keycode, int shift, int up) |
| 1494 | { | |
| 1495 | static int scan[] = { | |
| 1550dfd9 | 1496 | 0x1c, 0x1d, 0x35, |
| 984263bc | 1497 | 0x37 | SCAN_PREFIX_SHIFT, /* PrintScreen */ |
| 1550dfd9 MD |
1498 | 0x38, 0x47, 0x48, 0x49, 0x4b, 0x4d, 0x4f, |
| 1499 | 0x50, 0x51, 0x52, 0x53, | |
| 984263bc MD |
1500 | 0x46, /* XXX Pause/Break */ |
| 1501 | 0x5b, 0x5c, 0x5d, | |
| 1502 | }; | |
| 1503 | int scancode; | |
| 1504 | ||
| 1505 | scancode = keycode; | |
| 1506 | if ((keycode >= 89) && (keycode < 89 + sizeof(scan)/sizeof(scan[0]))) | |
| 1507 | scancode = scan[keycode - 89] | SCAN_PREFIX_E0; | |
| 1508 | /* Pause/Break */ | |
| 1509 | if ((keycode == 104) && !(shift & (MOD_CONTROL_L | MOD_CONTROL_R))) | |
| 1510 | scancode = 0x45 | SCAN_PREFIX_E1 | SCAN_PREFIX_CTL; | |
| 1511 | if (shift & (MOD_SHIFT_L | MOD_SHIFT_R)) | |
| 1512 | scancode &= ~SCAN_PREFIX_SHIFT; | |
| 1513 | return (scancode | (up ? SCAN_RELEASE : SCAN_PRESS)); | |
| 1514 | } | |
| 1515 | #endif /* UKBD_EMULATE_ATSCANCODE */ | |
| 1516 | ||
| 6ed427ca | 1517 | static int |
| 984263bc MD |
1518 | ukbd_driver_load(module_t mod, int what, void *arg) |
| 1519 | { | |
| 1520 | switch (what) { | |
| 1521 | case MOD_LOAD: | |
| 1522 | kbd_add_driver(&ukbd_kbd_driver); | |
| 1523 | break; | |
| 1524 | case MOD_UNLOAD: | |
| 1525 | kbd_delete_driver(&ukbd_kbd_driver); | |
| 1526 | break; | |
| 1527 | } | |
| 1528 | return usbd_driver_load(mod, what, 0); | |
| 1529 | } |