1 1.165 mlelstv /* $NetBSD: ukbd.c,v 1.165 2024/12/10 11:21:30 mlelstv Exp $ */ 2 1.1 augustss 3 1.1 augustss /* 4 1.1 augustss * Copyright (c) 1998 The NetBSD Foundation, Inc. 5 1.1 augustss * All rights reserved. 6 1.1 augustss * 7 1.11 augustss * This code is derived from software contributed to The NetBSD Foundation 8 1.59 augustss * by Lennart Augustsson (lennart (at) augustsson.net) at 9 1.11 augustss * Carlstedt Research & Technology. 10 1.1 augustss * 11 1.1 augustss * Redistribution and use in source and binary forms, with or without 12 1.1 augustss * modification, are permitted provided that the following conditions 13 1.1 augustss * are met: 14 1.1 augustss * 1. Redistributions of source code must retain the above copyright 15 1.1 augustss * notice, this list of conditions and the following disclaimer. 16 1.1 augustss * 2. Redistributions in binary form must reproduce the above copyright 17 1.1 augustss * notice, this list of conditions and the following disclaimer in the 18 1.1 augustss * documentation and/or other materials provided with the distribution. 19 1.1 augustss * 20 1.1 augustss * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 1.1 augustss * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 1.1 augustss * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 1.1 augustss * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 1.1 augustss * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 1.1 augustss * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 1.1 augustss * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 1.1 augustss * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 1.1 augustss * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 1.1 augustss * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 1.1 augustss * POSSIBILITY OF SUCH DAMAGE. 31 1.1 augustss */ 32 1.1 augustss 33 1.17 augustss /* 34 1.85 augustss * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf 35 1.17 augustss */ 36 1.72 lukem 37 1.72 lukem #include <sys/cdefs.h> 38 1.165 mlelstv __KERNEL_RCSID(0, "$NetBSD: ukbd.c,v 1.165 2024/12/10 11:21:30 mlelstv Exp $"); 39 1.125 christos 40 1.125 christos #ifdef _KERNEL_OPT 41 1.134 skrll #include "opt_ddb.h" 42 1.125 christos #include "opt_ukbd.h" 43 1.125 christos #include "opt_ukbd_layout.h" 44 1.132 jakllsch #include "opt_usb.h" 45 1.151 pgoyette #include "opt_usbverbose.h" 46 1.125 christos #include "opt_wsdisplay_compat.h" 47 1.125 christos #endif /* _KERNEL_OPT */ 48 1.17 augustss 49 1.1 augustss #include <sys/param.h> 50 1.164 riastrad 51 1.57 thorpej #include <sys/callout.h> 52 1.1 augustss #include <sys/device.h> 53 1.164 riastrad #include <sys/file.h> 54 1.1 augustss #include <sys/ioctl.h> 55 1.164 riastrad #include <sys/kernel.h> 56 1.164 riastrad #include <sys/poll.h> 57 1.164 riastrad #include <sys/proc.h> 58 1.1 augustss #include <sys/select.h> 59 1.164 riastrad #include <sys/systm.h> 60 1.1 augustss #include <sys/vnode.h> 61 1.1 augustss 62 1.164 riastrad #include <dev/hid/hid.h> 63 1.164 riastrad 64 1.164 riastrad #include <dev/usb/uhidev.h> 65 1.164 riastrad #include <dev/usb/ukbdvar.h> 66 1.1 augustss #include <dev/usb/usb.h> 67 1.164 riastrad #include <dev/usb/usb_quirks.h> 68 1.164 riastrad #include <dev/usb/usbdevs.h> 69 1.1 augustss #include <dev/usb/usbdi.h> 70 1.1 augustss #include <dev/usb/usbdi_util.h> 71 1.117 mrg #include <dev/usb/usbdivar.h> 72 1.164 riastrad #include <dev/usb/usbhid.h> 73 1.1 augustss 74 1.2 augustss #include <dev/wscons/wsconsio.h> 75 1.2 augustss #include <dev/wscons/wskbdvar.h> 76 1.2 augustss #include <dev/wscons/wsksymdef.h> 77 1.2 augustss #include <dev/wscons/wsksymvar.h> 78 1.2 augustss 79 1.62 augustss #ifdef UKBD_DEBUG 80 1.108 dyoung #define DPRINTF(x) if (ukbddebug) printf x 81 1.108 dyoung #define DPRINTFN(n,x) if (ukbddebug>(n)) printf x 82 1.1 augustss int ukbddebug = 0; 83 1.1 augustss #else 84 1.1 augustss #define DPRINTF(x) 85 1.1 augustss #define DPRINTFN(n,x) 86 1.1 augustss #endif 87 1.1 augustss 88 1.138 jakllsch #define MAXKEYCODE 32 89 1.138 jakllsch #define MAXKEYS 256 90 1.2 augustss 91 1.1 augustss struct ukbd_data { 92 1.138 jakllsch uint8_t keys[MAXKEYS/NBBY]; 93 1.1 augustss }; 94 1.1 augustss 95 1.23 augustss #define PRESS 0x000 96 1.23 augustss #define RELEASE 0x100 97 1.23 augustss #define CODEMASK 0x0ff 98 1.1 augustss 99 1.109 phx struct ukbd_keycodetrans { 100 1.131 skrll uint16_t from; 101 1.131 skrll uint16_t to; 102 1.109 phx }; 103 1.109 phx 104 1.112 macallan #define IS_PMF 0x8000 105 1.112 macallan 106 1.109 phx Static const struct ukbd_keycodetrans trtab_apple_fn[] = { 107 1.109 phx { 0x0c, 0x5d }, /* i -> KP 5 */ 108 1.109 phx { 0x0d, 0x59 }, /* j -> KP 1 */ 109 1.109 phx { 0x0e, 0x5a }, /* k -> KP 2 */ 110 1.109 phx { 0x0f, 0x5b }, /* l -> KP 3 */ 111 1.109 phx { 0x10, 0x62 }, /* m -> KP 0 */ 112 1.109 phx { 0x12, 0x5e }, /* o -> KP 6 */ 113 1.109 phx { 0x13, 0x55 }, /* o -> KP * */ 114 1.109 phx { 0x18, 0x5c }, /* u -> KP 4 */ 115 1.109 phx { 0x0c, 0x5d }, /* i -> KP 5 */ 116 1.109 phx { 0x2a, 0x4c }, /* Backspace -> Delete */ 117 1.109 phx { 0x28, 0x49 }, /* Return -> Insert */ 118 1.109 phx { 0x24, 0x5f }, /* 7 -> KP 7 */ 119 1.109 phx { 0x25, 0x60 }, /* 8 -> KP 8 */ 120 1.109 phx { 0x26, 0x61 }, /* 9 -> KP 9 */ 121 1.109 phx { 0x27, 0x54 }, /* 0 -> KP / */ 122 1.109 phx { 0x2d, 0x67 }, /* - -> KP = */ 123 1.109 phx { 0x33, 0x56 }, /* ; -> KP - */ 124 1.109 phx { 0x37, 0x63 }, /* . -> KP . */ 125 1.109 phx { 0x38, 0x57 }, /* / -> KP + */ 126 1.143 macallan { 0x3a, IS_PMF | PMFE_DISPLAY_BRIGHTNESS_DOWN }, 127 1.143 macallan { 0x3b, IS_PMF | PMFE_DISPLAY_BRIGHTNESS_UP }, 128 1.143 macallan { 0x3c, IS_PMF | PMFE_AUDIO_VOLUME_TOGGLE }, 129 1.143 macallan { 0x3d, IS_PMF | PMFE_AUDIO_VOLUME_DOWN }, 130 1.143 macallan { 0x3e, IS_PMF | PMFE_AUDIO_VOLUME_UP }, 131 1.143 macallan { 0x3f, 0xd6 }, /* num lock */ 132 1.109 phx { 0x40, 0xd7 }, 133 1.147 macallan { 0x41, IS_PMF | PMFE_KEYBOARD_BRIGHTNESS_TOGGLE }, 134 1.147 macallan { 0x42, IS_PMF | PMFE_KEYBOARD_BRIGHTNESS_DOWN }, 135 1.147 macallan { 0x43, IS_PMF | PMFE_KEYBOARD_BRIGHTNESS_UP }, 136 1.109 phx { 0x44, 0xdb }, 137 1.109 phx { 0x45, 0xdc }, 138 1.109 phx { 0x4f, 0x4d }, /* Right -> End */ 139 1.109 phx { 0x50, 0x4a }, /* Left -> Home */ 140 1.109 phx { 0x51, 0x4e }, /* Down -> PageDown */ 141 1.109 phx { 0x52, 0x4b }, /* Up -> PageUp */ 142 1.109 phx { 0x00, 0x00 } 143 1.109 phx }; 144 1.109 phx 145 1.109 phx Static const struct ukbd_keycodetrans trtab_apple_iso[] = { 146 1.109 phx { 0x35, 0x64 }, /* swap the key above tab with key right of shift */ 147 1.109 phx { 0x64, 0x35 }, 148 1.109 phx { 0x31, 0x32 }, /* key left of return is Europe1, not "\|" */ 149 1.109 phx { 0x00, 0x00 } 150 1.109 phx }; 151 1.109 phx 152 1.113 macallan #ifdef GDIUM_KEYBOARD_HACK 153 1.125 christos Static const struct ukbd_keycodetrans trtab_gdium_fn[] = { 154 1.111 macallan #ifdef notyet 155 1.119 khorben { 58, 0 }, /* F1 -> toggle camera */ 156 1.119 khorben { 59, 0 }, /* F2 -> toggle wireless */ 157 1.111 macallan #endif 158 1.119 khorben { 60, IS_PMF | PMFE_AUDIO_VOLUME_TOGGLE }, 159 1.119 khorben { 61, IS_PMF | PMFE_AUDIO_VOLUME_UP }, 160 1.119 khorben { 62, IS_PMF | PMFE_AUDIO_VOLUME_DOWN }, 161 1.111 macallan #ifdef notyet 162 1.119 khorben { 63, 0 }, /* F6 -> toggle ext. video */ 163 1.119 khorben { 64, 0 }, /* F7 -> toggle mouse */ 164 1.112 macallan #endif 165 1.119 khorben { 65, IS_PMF | PMFE_DISPLAY_BRIGHTNESS_UP }, 166 1.119 khorben { 66, IS_PMF | PMFE_DISPLAY_BRIGHTNESS_DOWN }, 167 1.112 macallan #ifdef notyet 168 1.119 khorben { 67, 0 }, /* F10 -> suspend */ 169 1.119 khorben { 68, 0 }, /* F11 -> user1 */ 170 1.119 khorben { 69, 0 }, /* F12 -> user2 */ 171 1.119 khorben { 70, 0 }, /* print screen -> sysrq */ 172 1.119 khorben #endif 173 1.119 khorben { 76, 71 }, /* delete -> scroll lock */ 174 1.119 khorben { 81, 78 }, /* down -> page down */ 175 1.119 khorben { 82, 75 }, /* up -> page up */ 176 1.119 khorben { 0, 0 } 177 1.111 macallan }; 178 1.113 macallan #endif 179 1.111 macallan 180 1.120 khorben Static const struct ukbd_keycodetrans trtab_generic[] = { 181 1.120 khorben { 0x7f, IS_PMF | PMFE_AUDIO_VOLUME_TOGGLE }, 182 1.120 khorben { 0x80, IS_PMF | PMFE_AUDIO_VOLUME_UP }, 183 1.120 khorben { 0x81, IS_PMF | PMFE_AUDIO_VOLUME_DOWN }, 184 1.120 khorben { 0x00, 0x00 } 185 1.120 khorben }; 186 1.120 khorben 187 1.116 mrg #if defined(WSDISPLAY_COMPAT_RAWKBD) 188 1.5 augustss #define NN 0 /* no translation */ 189 1.82 augustss /* 190 1.23 augustss * Translate USB keycodes to US keyboard XT scancodes. 191 1.76 augustss * Scancodes >= 0x80 represent EXTENDED keycodes. 192 1.76 augustss * 193 1.104 jakllsch * See http://www.microsoft.com/whdc/archive/scancode.mspx 194 1.104 jakllsch * 195 1.107 sborrill * Note: a real pckbd(4) has more complexity in its 196 1.104 jakllsch * protocol for some keys than this translation implements. 197 1.107 sborrill * For example, some keys generate Fake ShiftL events (e0 2a) 198 1.107 sborrill * before the actual key sequence. 199 1.19 augustss */ 200 1.131 skrll Static const uint8_t ukbd_trtab[256] = { 201 1.123 khorben NN, NN, NN, NN, 0x1e, 0x30, 0x2e, 0x20, /* 00 - 07 */ 202 1.123 khorben 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, /* 08 - 0f */ 203 1.123 khorben 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14, /* 10 - 17 */ 204 1.123 khorben 0x16, 0x2f, 0x11, 0x2d, 0x15, 0x2c, 0x02, 0x03, /* 18 - 1f */ 205 1.123 khorben 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, /* 20 - 27 */ 206 1.123 khorben 0x1c, 0x01, 0x0e, 0x0f, 0x39, 0x0c, 0x0d, 0x1a, /* 28 - 2f */ 207 1.123 khorben 0x1b, 0x2b, 0x2b, 0x27, 0x28, 0x29, 0x33, 0x34, /* 30 - 37 */ 208 1.123 khorben 0x35, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, /* 38 - 3f */ 209 1.123 khorben 0x41, 0x42, 0x43, 0x44, 0x57, 0x58, 0xb7, 0x46, /* 40 - 47 */ 210 1.123 khorben 0x7f, 0xd2, 0xc7, 0xc9, 0xd3, 0xcf, 0xd1, 0xcd, /* 48 - 4f */ 211 1.123 khorben 0xcb, 0xd0, 0xc8, 0x45, 0xb5, 0x37, 0x4a, 0x4e, /* 50 - 57 */ 212 1.123 khorben 0x9c, 0x4f, 0x50, 0x51, 0x4b, 0x4c, 0x4d, 0x47, /* 58 - 5f */ 213 1.123 khorben 0x48, 0x49, 0x52, 0x53, 0x56, 0xdd, 0xdf, 0x59, /* 60 - 67 */ 214 1.123 khorben 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, NN, /* 68 - 6f */ 215 1.123 khorben NN, NN, NN, NN, 0x84, 0x85, 0x87, 0x88, /* 70 - 77 */ 216 1.123 khorben 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, NN, /* 78 - 7f */ 217 1.123 khorben NN, NN, NN, NN, NN, 0x7e, NN, 0x73, /* 80 - 87 */ 218 1.123 khorben 0x70, 0x7d, 0x79, 0x7b, 0x5c, NN, NN, NN, /* 88 - 8f */ 219 1.123 khorben NN, NN, 0x78, 0x77, 0x76, NN, NN, NN, /* 90 - 97 */ 220 1.123 khorben NN, NN, NN, NN, NN, NN, NN, NN, /* 98 - 9f */ 221 1.123 khorben NN, NN, NN, NN, NN, NN, NN, NN, /* a0 - a7 */ 222 1.123 khorben NN, NN, NN, NN, NN, NN, NN, NN, /* a8 - af */ 223 1.123 khorben NN, NN, NN, NN, NN, NN, NN, NN, /* b0 - b7 */ 224 1.123 khorben NN, NN, NN, NN, NN, NN, NN, NN, /* b8 - bf */ 225 1.123 khorben NN, NN, NN, NN, NN, NN, NN, NN, /* c0 - c7 */ 226 1.123 khorben NN, NN, NN, NN, NN, NN, NN, NN, /* c8 - cf */ 227 1.123 khorben NN, NN, NN, NN, NN, NN, NN, NN, /* d0 - d7 */ 228 1.123 khorben NN, NN, NN, NN, NN, NN, NN, NN, /* d8 - df */ 229 1.123 khorben 0x1d, 0x2a, 0x38, 0xdb, 0x9d, 0x36, 0xb8, 0xdc, /* e0 - e7 */ 230 1.123 khorben NN, NN, NN, NN, NN, NN, NN, NN, /* e8 - ef */ 231 1.123 khorben NN, NN, NN, NN, NN, NN, NN, NN, /* f0 - f7 */ 232 1.123 khorben NN, NN, NN, NN, NN, NN, NN, NN, /* f8 - ff */ 233 1.1 augustss }; 234 1.116 mrg #endif /* defined(WSDISPLAY_COMPAT_RAWKBD) */ 235 1.1 augustss 236 1.1 augustss #define KEY_ERROR 0x01 237 1.1 augustss 238 1.1 augustss struct ukbd_softc { 239 1.159 riastrad device_t sc_dev; 240 1.159 riastrad struct uhidev *sc_hdev; 241 1.158 riastrad struct usbd_device *sc_udev; 242 1.158 riastrad struct usbd_interface *sc_iface; 243 1.159 riastrad int sc_report_id; 244 1.1 augustss 245 1.1 augustss struct ukbd_data sc_ndata; 246 1.1 augustss struct ukbd_data sc_odata; 247 1.138 jakllsch struct hid_location sc_keyloc[MAXKEYS]; 248 1.138 jakllsch uint8_t sc_keyuse[MAXKEYS]; 249 1.138 jakllsch u_int sc_nkeyloc; 250 1.75 augustss 251 1.75 augustss struct hid_location sc_keycodeloc; 252 1.75 augustss u_int sc_nkeycode; 253 1.1 augustss 254 1.109 phx u_int sc_flags; /* flags */ 255 1.109 phx #define FLAG_ENABLED 0x0001 256 1.109 phx #define FLAG_POLLING 0x0002 257 1.109 phx #define FLAG_DEBOUNCE 0x0004 /* for quirk handling */ 258 1.109 phx #define FLAG_APPLE_FIX_ISO 0x0008 259 1.109 phx #define FLAG_APPLE_FN 0x0010 260 1.111 macallan #define FLAG_GDIUM_FN 0x0020 261 1.109 phx #define FLAG_FN_PRESSED 0x0100 /* FN key is held down */ 262 1.109 phx #define FLAG_FN_ALT 0x0200 /* Last Alt key was FN-Alt = AltGr */ 263 1.160 mlelstv #define FLAG_NO_CONSOLE 0x0400 /* Don't attach as console */ 264 1.1 augustss 265 1.29 thorpej int sc_console_keyboard; /* we are the console keyboard */ 266 1.29 thorpej 267 1.109 phx struct callout sc_delay; /* for quirk handling */ 268 1.146 tih #define MAXPENDING 32 269 1.146 tih struct ukbd_data sc_data[MAXPENDING]; 270 1.146 tih size_t sc_data_w, sc_data_r; 271 1.62 augustss 272 1.109 phx struct hid_location sc_apple_fn; 273 1.75 augustss struct hid_location sc_numloc; 274 1.75 augustss struct hid_location sc_capsloc; 275 1.75 augustss struct hid_location sc_scroloc; 276 1.121 khorben struct hid_location sc_compose; 277 1.2 augustss int sc_leds; 278 1.129 skrll struct usb_task sc_ledtask; 279 1.156 riastrad struct callout sc_ledreset; 280 1.156 riastrad int sc_leds_set; 281 1.97 dyoung device_t sc_wskbddev; 282 1.57 thorpej 283 1.23 augustss #if defined(WSDISPLAY_COMPAT_RAWKBD) 284 1.87 augustss int sc_rawkbd; 285 1.87 augustss #if defined(UKBD_REPEAT) 286 1.108 dyoung struct callout sc_rawrepeat_ch; 287 1.20 augustss #define REP_DELAY1 400 288 1.20 augustss #define REP_DELAYN 100 289 1.20 augustss int sc_nrep; 290 1.20 augustss char sc_rep[MAXKEYS]; 291 1.87 augustss #endif /* defined(UKBD_REPEAT) */ 292 1.23 augustss #endif /* defined(WSDISPLAY_COMPAT_RAWKBD) */ 293 1.3 augustss 294 1.84 augustss int sc_spl; 295 1.23 augustss int sc_npollchar; 296 1.131 skrll uint16_t sc_pollchars[MAXKEYS]; 297 1.40 augustss 298 1.162 mrg bool sc_dying; 299 1.162 mrg bool sc_attached; 300 1.1 augustss }; 301 1.1 augustss 302 1.62 augustss #ifdef UKBD_DEBUG 303 1.62 augustss #define UKBDTRACESIZE 64 304 1.62 augustss struct ukbdtraceinfo { 305 1.62 augustss int unit; 306 1.62 augustss struct timeval tv; 307 1.62 augustss struct ukbd_data ud; 308 1.62 augustss }; 309 1.62 augustss struct ukbdtraceinfo ukbdtracedata[UKBDTRACESIZE]; 310 1.62 augustss int ukbdtraceindex = 0; 311 1.62 augustss int ukbdtrace = 0; 312 1.62 augustss void ukbdtracedump(void); 313 1.62 augustss void 314 1.62 augustss ukbdtracedump(void) 315 1.62 augustss { 316 1.138 jakllsch size_t i, j; 317 1.62 augustss for (i = 0; i < UKBDTRACESIZE; i++) { 318 1.82 augustss struct ukbdtraceinfo *p = 319 1.62 augustss &ukbdtracedata[(i+ukbdtraceindex)%UKBDTRACESIZE]; 320 1.138 jakllsch printf("%"PRIu64".%06"PRIu64":", p->tv.tv_sec, 321 1.138 jakllsch (uint64_t)p->tv.tv_usec); 322 1.138 jakllsch for (j = 0; j < MAXKEYS; j++) { 323 1.138 jakllsch if (isset(p->ud.keys, j)) 324 1.138 jakllsch printf(" %zu", j); 325 1.138 jakllsch } 326 1.138 jakllsch printf(".\n"); 327 1.62 augustss } 328 1.62 augustss } 329 1.62 augustss #endif 330 1.62 augustss 331 1.1 augustss #define UKBDUNIT(dev) (minor(dev)) 332 1.1 augustss #define UKBD_CHUNK 128 /* chunk size for read */ 333 1.1 augustss #define UKBD_BSIZE 1020 /* buffer size */ 334 1.1 augustss 335 1.58 augustss Static int ukbd_is_console; 336 1.31 thorpej 337 1.60 augustss Static void ukbd_cngetc(void *, u_int *, int *); 338 1.60 augustss Static void ukbd_cnpollc(void *, int); 339 1.3 augustss 340 1.8 drochner const struct wskbd_consops ukbd_consops = { 341 1.124 mrg .getc = ukbd_cngetc, 342 1.124 mrg .pollc = ukbd_cnpollc, 343 1.124 mrg .bell = NULL, 344 1.8 drochner }; 345 1.8 drochner 346 1.131 skrll Static const char *ukbd_parse_desc(struct ukbd_softc *); 347 1.75 augustss 348 1.159 riastrad Static void ukbd_intr(void *, void *, u_int); 349 1.131 skrll Static void ukbd_decode(struct ukbd_softc *, struct ukbd_data *); 350 1.131 skrll Static void ukbd_delayed_decode(void *); 351 1.2 augustss 352 1.60 augustss Static int ukbd_enable(void *, int); 353 1.60 augustss Static void ukbd_set_leds(void *, int); 354 1.129 skrll Static void ukbd_set_leds_task(void *); 355 1.153 jmcneill Static void ukbd_delayed_leds_off(void *); 356 1.23 augustss 357 1.95 christos Static int ukbd_ioctl(void *, u_long, void *, int, struct lwp *); 358 1.88 jonathan #if defined(WSDISPLAY_COMPAT_RAWKBD) && defined(UKBD_REPEAT) 359 1.60 augustss Static void ukbd_rawrepeat(void *v); 360 1.48 mjacob #endif 361 1.1 augustss 362 1.8 drochner const struct wskbd_accessops ukbd_accessops = { 363 1.8 drochner ukbd_enable, 364 1.8 drochner ukbd_set_leds, 365 1.8 drochner ukbd_ioctl, 366 1.8 drochner }; 367 1.8 drochner 368 1.139 bouyer extern const struct wscons_keydesc hidkbd_keydesctab[]; 369 1.23 augustss 370 1.8 drochner const struct wskbd_mapdata ukbd_keymapdata = { 371 1.139 bouyer hidkbd_keydesctab, 372 1.86 augustss #if defined(UKBD_LAYOUT) 373 1.66 augustss UKBD_LAYOUT, 374 1.86 augustss #elif defined(PCKBD_LAYOUT) 375 1.86 augustss PCKBD_LAYOUT, 376 1.66 augustss #else 377 1.8 drochner KB_US, 378 1.66 augustss #endif 379 1.8 drochner }; 380 1.8 drochner 381 1.160 mlelstv static const struct ukbd_type { 382 1.160 mlelstv struct usb_devno dev; 383 1.160 mlelstv int flags; 384 1.160 mlelstv } ukbd_devs[] = { 385 1.160 mlelstv #define UKBD_DEV(v, p, f) \ 386 1.160 mlelstv { { USB_VENDOR_##v, USB_PRODUCT_##v##_##p }, (f) } 387 1.160 mlelstv #ifdef GDIUM_KEYBOARD_HACK 388 1.160 mlelstv UKBD_DEV(CYPRESS, LPRDK, FLAG_GDIUM_FN), 389 1.160 mlelstv #endif 390 1.160 mlelstv UKBD_DEV(YUBICO, YUBIKEY4MODE1, FLAG_NO_CONSOLE), 391 1.160 mlelstv UKBD_DEV(YUBICO, YUBIKEY4MODE2, FLAG_NO_CONSOLE), 392 1.160 mlelstv UKBD_DEV(YUBICO, YUBIKEY4MODE6, FLAG_NO_CONSOLE) 393 1.160 mlelstv }; 394 1.160 mlelstv #define ukbd_lookup(v, p) \ 395 1.160 mlelstv ((const struct ukbd_type *)usb_lookup(ukbd_devs, v, p)) 396 1.160 mlelstv 397 1.100 cube static int ukbd_match(device_t, cfdata_t, void *); 398 1.97 dyoung static void ukbd_attach(device_t, device_t, void *); 399 1.97 dyoung static int ukbd_detach(device_t, int); 400 1.97 dyoung static int ukbd_activate(device_t, enum devact); 401 1.97 dyoung static void ukbd_childdet(device_t, device_t); 402 1.97 dyoung 403 1.142 mrg 404 1.97 dyoung 405 1.100 cube CFATTACH_DECL2_NEW(ukbd, sizeof(struct ukbd_softc), ukbd_match, ukbd_attach, 406 1.97 dyoung ukbd_detach, ukbd_activate, NULL, ukbd_childdet); 407 1.1 augustss 408 1.75 augustss int 409 1.100 cube ukbd_match(device_t parent, cfdata_t match, void *aux) 410 1.1 augustss { 411 1.75 augustss struct uhidev_attach_arg *uha = aux; 412 1.75 augustss int size; 413 1.75 augustss void *desc; 414 1.82 augustss 415 1.75 augustss uhidev_get_report_desc(uha->parent, &desc, &size); 416 1.75 augustss if (!hid_is_collection(desc, size, uha->reportid, 417 1.75 augustss HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_KEYBOARD))) 418 1.131 skrll return UMATCH_NONE; 419 1.75 augustss 420 1.131 skrll return UMATCH_IFACECLASS; 421 1.1 augustss } 422 1.1 augustss 423 1.75 augustss void 424 1.97 dyoung ukbd_attach(device_t parent, device_t self, void *aux) 425 1.1 augustss { 426 1.97 dyoung struct ukbd_softc *sc = device_private(self); 427 1.75 augustss struct uhidev_attach_arg *uha = aux; 428 1.131 skrll uint32_t qflags; 429 1.75 augustss const char *parseerr; 430 1.2 augustss struct wskbddev_attach_args a; 431 1.160 mlelstv const struct ukbd_type *ukt; 432 1.82 augustss 433 1.159 riastrad sc->sc_dev = self; 434 1.159 riastrad sc->sc_hdev = uha->parent; 435 1.158 riastrad sc->sc_udev = uha->uiaa->uiaa_device; 436 1.158 riastrad sc->sc_iface = uha->uiaa->uiaa_iface; 437 1.159 riastrad sc->sc_report_id = uha->reportid; 438 1.109 phx sc->sc_flags = 0; 439 1.75 augustss 440 1.127 soren aprint_naive("\n"); 441 1.127 soren 442 1.101 jmcneill if (!pmf_device_register(self, NULL, NULL)) { 443 1.101 jmcneill aprint_normal("\n"); 444 1.101 jmcneill aprint_error_dev(self, "couldn't establish power handler\n"); 445 1.101 jmcneill } 446 1.101 jmcneill 447 1.75 augustss parseerr = ukbd_parse_desc(sc); 448 1.75 augustss if (parseerr != NULL) { 449 1.98 cegger aprint_normal("\n"); 450 1.100 cube aprint_error_dev(self, "attach failed, %s\n", parseerr); 451 1.108 dyoung return; 452 1.1 augustss } 453 1.82 augustss 454 1.109 phx /* Quirks */ 455 1.158 riastrad qflags = usbd_get_quirks(sc->sc_udev)->uq_flags; 456 1.109 phx if (qflags & UQ_SPUR_BUT_UP) 457 1.109 phx sc->sc_flags |= FLAG_DEBOUNCE; 458 1.109 phx if (qflags & UQ_APPLE_ISO) 459 1.109 phx sc->sc_flags |= FLAG_APPLE_FIX_ISO; 460 1.109 phx 461 1.160 mlelstv /* Other Quirks */ 462 1.160 mlelstv ukt = ukbd_lookup(uha->uiaa->uiaa_vendor, uha->uiaa->uiaa_product); 463 1.160 mlelstv if (ukt) 464 1.160 mlelstv sc->sc_flags |= ukt->flags; 465 1.111 macallan 466 1.148 gdt #ifdef USBVERBOSE 467 1.138 jakllsch aprint_normal(": %d Variable keys, %d Array codes", sc->sc_nkeyloc, 468 1.75 augustss sc->sc_nkeycode); 469 1.109 phx if (sc->sc_flags & FLAG_APPLE_FN) 470 1.109 phx aprint_normal(", apple fn key"); 471 1.109 phx if (sc->sc_flags & FLAG_APPLE_FIX_ISO) 472 1.109 phx aprint_normal(", fix apple iso"); 473 1.111 macallan if (sc->sc_flags & FLAG_GDIUM_FN) 474 1.111 macallan aprint_normal(", Gdium fn key"); 475 1.75 augustss #endif 476 1.100 cube aprint_normal("\n"); 477 1.1 augustss 478 1.160 mlelstv if ((sc->sc_flags & FLAG_NO_CONSOLE) == 0) { 479 1.160 mlelstv /* 480 1.160 mlelstv * Remember if we're the console keyboard. 481 1.160 mlelstv * 482 1.160 mlelstv * XXX This always picks the first keyboard on the 483 1.160 mlelstv * first USB bus, but what else can we really do? 484 1.160 mlelstv */ 485 1.160 mlelstv if ((sc->sc_console_keyboard = ukbd_is_console) != 0) { 486 1.160 mlelstv /* Don't let any other keyboard have it. */ 487 1.160 mlelstv ukbd_is_console = 0; 488 1.160 mlelstv } 489 1.29 thorpej } 490 1.29 thorpej 491 1.31 thorpej if (sc->sc_console_keyboard) { 492 1.141 christos DPRINTF(("%s: console keyboard sc=%p\n", __func__, sc)); 493 1.31 thorpej wskbd_cnattach(&ukbd_consops, sc, &ukbd_keymapdata); 494 1.34 wrstuden ukbd_enable(sc, 1); 495 1.31 thorpej } 496 1.29 thorpej 497 1.29 thorpej a.console = sc->sc_console_keyboard; 498 1.8 drochner 499 1.8 drochner a.keymap = &ukbd_keymapdata; 500 1.8 drochner 501 1.8 drochner a.accessops = &ukbd_accessops; 502 1.2 augustss a.accesscookie = sc; 503 1.8 drochner 504 1.87 augustss #ifdef UKBD_REPEAT 505 1.108 dyoung callout_init(&sc->sc_rawrepeat_ch, 0); 506 1.87 augustss #endif 507 1.57 thorpej 508 1.108 dyoung callout_init(&sc->sc_delay, 0); 509 1.62 augustss 510 1.146 tih sc->sc_data_w = 0; 511 1.146 tih sc->sc_data_r = 0; 512 1.146 tih 513 1.130 mrg usb_init_task(&sc->sc_ledtask, ukbd_set_leds_task, sc, 0); 514 1.156 riastrad callout_init(&sc->sc_ledreset, 0); 515 1.129 skrll 516 1.19 augustss /* Flash the leds; no real purpose, just shows we're alive. */ 517 1.121 khorben ukbd_set_leds(sc, WSKBD_LED_SCROLL | WSKBD_LED_NUM | WSKBD_LED_CAPS 518 1.121 khorben | WSKBD_LED_COMPOSE); 519 1.157 riastrad sc->sc_leds_set = 0; /* not explicitly set by wskbd yet */ 520 1.156 riastrad callout_reset(&sc->sc_ledreset, mstohz(400), ukbd_delayed_leds_off, 521 1.156 riastrad sc); 522 1.19 augustss 523 1.152 thorpej sc->sc_wskbddev = config_found(self, &a, wskbddevprint, CFARGS_NONE); 524 1.55 augustss 525 1.162 mrg sc->sc_attached = true; 526 1.162 mrg 527 1.108 dyoung return; 528 1.1 augustss } 529 1.1 augustss 530 1.8 drochner int 531 1.60 augustss ukbd_enable(void *v, int on) 532 1.8 drochner { 533 1.9 augustss struct ukbd_softc *sc = v; 534 1.165 mlelstv int error = 0; 535 1.9 augustss 536 1.40 augustss if (on && sc->sc_dying) 537 1.131 skrll return EIO; 538 1.40 augustss 539 1.141 christos DPRINTF(("%s: sc=%p on=%d\n", __func__, sc, on)); 540 1.9 augustss if (on) { 541 1.165 mlelstv if ((sc->sc_flags & FLAG_ENABLED) == 0) { 542 1.165 mlelstv error = uhidev_open(sc->sc_hdev, &ukbd_intr, sc); 543 1.165 mlelstv if (error == 0) 544 1.165 mlelstv sc->sc_flags |= FLAG_ENABLED; 545 1.165 mlelstv } 546 1.9 augustss } else { 547 1.165 mlelstv if ((sc->sc_flags & FLAG_ENABLED) != 0) { 548 1.165 mlelstv uhidev_close(sc->sc_hdev); 549 1.165 mlelstv sc->sc_flags &= ~FLAG_ENABLED; 550 1.165 mlelstv } 551 1.9 augustss } 552 1.165 mlelstv 553 1.165 mlelstv return error; 554 1.37 augustss } 555 1.37 augustss 556 1.97 dyoung 557 1.97 dyoung static void 558 1.97 dyoung ukbd_childdet(device_t self, device_t child) 559 1.97 dyoung { 560 1.97 dyoung struct ukbd_softc *sc = device_private(self); 561 1.97 dyoung 562 1.97 dyoung KASSERT(sc->sc_wskbddev == child); 563 1.97 dyoung sc->sc_wskbddev = NULL; 564 1.97 dyoung } 565 1.97 dyoung 566 1.37 augustss int 567 1.97 dyoung ukbd_activate(device_t self, enum devact act) 568 1.37 augustss { 569 1.97 dyoung struct ukbd_softc *sc = device_private(self); 570 1.40 augustss 571 1.40 augustss switch (act) { 572 1.40 augustss case DVACT_DEACTIVATE: 573 1.162 mrg sc->sc_dying = true; 574 1.105 dyoung return 0; 575 1.105 dyoung default: 576 1.105 dyoung return EOPNOTSUPP; 577 1.40 augustss } 578 1.37 augustss } 579 1.37 augustss 580 1.75 augustss int 581 1.97 dyoung ukbd_detach(device_t self, int flags) 582 1.37 augustss { 583 1.97 dyoung struct ukbd_softc *sc = device_private(self); 584 1.37 augustss int rv = 0; 585 1.37 augustss 586 1.141 christos DPRINTF(("%s: sc=%p flags=%d\n", __func__, sc, flags)); 587 1.46 augustss 588 1.101 jmcneill pmf_device_deregister(self); 589 1.101 jmcneill 590 1.162 mrg if (!sc->sc_attached) 591 1.162 mrg return rv; 592 1.162 mrg 593 1.37 augustss if (sc->sc_console_keyboard) { 594 1.51 augustss /* 595 1.51 augustss * Disconnect our consops and set ukbd_is_console 596 1.51 augustss * back to 1 so that the next USB keyboard attached 597 1.51 augustss * to the system will get it. 598 1.51 augustss * XXX Should notify some other keyboard that it can be 599 1.51 augustss * XXX console, if there are any other keyboards. 600 1.51 augustss */ 601 1.75 augustss printf("%s: was console keyboard\n", 602 1.159 riastrad device_xname(sc->sc_dev)); 603 1.50 augustss wskbd_cndetach(); 604 1.50 augustss ukbd_is_console = 1; 605 1.37 augustss } 606 1.45 augustss /* No need to do reference counting of ukbd, wskbd has all the goo. */ 607 1.47 augustss if (sc->sc_wskbddev != NULL) 608 1.37 augustss rv = config_detach(sc->sc_wskbddev, flags); 609 1.68 augustss 610 1.154 riastrad callout_halt(&sc->sc_delay, NULL); 611 1.156 riastrad callout_halt(&sc->sc_ledreset, NULL); 612 1.158 riastrad usb_rem_task_wait(sc->sc_udev, &sc->sc_ledtask, 613 1.154 riastrad USB_TASKQ_DRIVER, NULL); 614 1.154 riastrad 615 1.68 augustss /* The console keyboard does not get a disable call, so check pipe. */ 616 1.159 riastrad if (sc->sc_flags & FLAG_ENABLED) 617 1.159 riastrad uhidev_close(sc->sc_hdev); 618 1.55 augustss 619 1.131 skrll return rv; 620 1.1 augustss } 621 1.1 augustss 622 1.109 phx static void 623 1.109 phx ukbd_translate_keycodes(struct ukbd_softc *sc, struct ukbd_data *ud, 624 1.109 phx const struct ukbd_keycodetrans *tab) 625 1.109 phx { 626 1.109 phx const struct ukbd_keycodetrans *tp; 627 1.138 jakllsch struct ukbd_data oud; 628 1.109 phx int i; 629 1.109 phx 630 1.138 jakllsch oud = *ud; 631 1.138 jakllsch 632 1.138 jakllsch for (i = 4; i < MAXKEYS; i++) { 633 1.138 jakllsch if (isset(oud.keys, i)) 634 1.109 phx for (tp = tab; tp->from; tp++) 635 1.138 jakllsch if (tp->from == i) { 636 1.112 macallan if (tp->to & IS_PMF) { 637 1.159 riastrad pmf_event_inject(sc->sc_dev, 638 1.112 macallan tp->to & 0xff); 639 1.112 macallan } else 640 1.138 jakllsch setbit(ud->keys, tp->to); 641 1.138 jakllsch clrbit(ud->keys, i); 642 1.109 phx break; 643 1.109 phx } 644 1.109 phx } 645 1.109 phx } 646 1.109 phx 647 1.131 skrll static uint16_t 648 1.131 skrll ukbd_translate_modifier(struct ukbd_softc *sc, uint16_t key) 649 1.109 phx { 650 1.109 phx if ((sc->sc_flags & FLAG_APPLE_FN) && (key & CODEMASK) == 0x00e2) { 651 1.109 phx if ((key & ~CODEMASK) == PRESS) { 652 1.109 phx if (sc->sc_flags & FLAG_FN_PRESSED) { 653 1.109 phx /* pressed FN-Alt, translate to AltGr */ 654 1.109 phx key = 0x00e6 | PRESS; 655 1.109 phx sc->sc_flags |= FLAG_FN_ALT; 656 1.109 phx } 657 1.109 phx } else { 658 1.109 phx if (sc->sc_flags & FLAG_FN_ALT) { 659 1.109 phx /* released Alt, which was treated as FN-Alt */ 660 1.109 phx key = 0x00e6 | RELEASE; 661 1.109 phx sc->sc_flags &= ~FLAG_FN_ALT; 662 1.109 phx } 663 1.109 phx } 664 1.109 phx } 665 1.109 phx return key; 666 1.109 phx } 667 1.109 phx 668 1.1 augustss void 669 1.159 riastrad ukbd_intr(void *cookie, void *ibuf, u_int len) 670 1.1 augustss { 671 1.159 riastrad struct ukbd_softc *sc = cookie; 672 1.1 augustss struct ukbd_data *ud = &sc->sc_ndata; 673 1.75 augustss int i; 674 1.76 augustss 675 1.76 augustss #ifdef UKBD_DEBUG 676 1.76 augustss if (ukbddebug > 5) { 677 1.76 augustss printf("ukbd_intr: data"); 678 1.76 augustss for (i = 0; i < len; i++) 679 1.145 christos printf(" 0x%02x", ((u_char *)ibuf)[i]); 680 1.76 augustss printf("\n"); 681 1.76 augustss } 682 1.76 augustss #endif 683 1.76 augustss 684 1.138 jakllsch memset(ud->keys, 0, sizeof(ud->keys)); 685 1.138 jakllsch 686 1.138 jakllsch for (i = 0; i < sc->sc_nkeyloc; i++) 687 1.138 jakllsch if (hid_get_data(ibuf, &sc->sc_keyloc[i])) 688 1.138 jakllsch setbit(ud->keys, sc->sc_keyuse[i]); 689 1.138 jakllsch 690 1.138 jakllsch const uint8_t * const scancode = (char *)ibuf + sc->sc_keycodeloc.pos / 8; 691 1.138 jakllsch const uint16_t Keyboard_NoEvent = 0x0000; 692 1.138 jakllsch for (i = 0; i < sc->sc_nkeycode; i++) { 693 1.138 jakllsch if (scancode[i] != Keyboard_NoEvent) 694 1.138 jakllsch setbit(ud->keys, scancode[i]); 695 1.138 jakllsch } 696 1.1 augustss 697 1.109 phx if (sc->sc_flags & FLAG_APPLE_FN) { 698 1.109 phx if (hid_get_data(ibuf, &sc->sc_apple_fn)) { 699 1.109 phx sc->sc_flags |= FLAG_FN_PRESSED; 700 1.109 phx ukbd_translate_keycodes(sc, ud, trtab_apple_fn); 701 1.109 phx } 702 1.109 phx else 703 1.109 phx sc->sc_flags &= ~FLAG_FN_PRESSED; 704 1.109 phx } 705 1.113 macallan 706 1.113 macallan #ifdef GDIUM_KEYBOARD_HACK 707 1.111 macallan if (sc->sc_flags & FLAG_GDIUM_FN) { 708 1.111 macallan if (sc->sc_flags & FLAG_FN_PRESSED) { 709 1.111 macallan ukbd_translate_keycodes(sc, ud, trtab_gdium_fn); 710 1.111 macallan } 711 1.111 macallan } 712 1.113 macallan #endif 713 1.109 phx 714 1.120 khorben ukbd_translate_keycodes(sc, ud, trtab_generic); 715 1.120 khorben 716 1.109 phx if ((sc->sc_flags & FLAG_DEBOUNCE) && !(sc->sc_flags & FLAG_POLLING)) { 717 1.62 augustss /* 718 1.62 augustss * Some keyboards have a peculiar quirk. They sometimes 719 1.62 augustss * generate a key up followed by a key down for the same 720 1.62 augustss * key after about 10 ms. 721 1.62 augustss * We avoid this bug by holding off decoding for 20 ms. 722 1.146 tih * Note that this comes at a cost: we deliberately overwrite 723 1.146 tih * the data for any keyboard event that is followed by 724 1.146 tih * another one within this time window. 725 1.62 augustss */ 726 1.146 tih if (sc->sc_data_w == sc->sc_data_r) { 727 1.146 tih sc->sc_data_w = (sc->sc_data_w + 1) % MAXPENDING; 728 1.146 tih } 729 1.146 tih sc->sc_data[sc->sc_data_w] = *ud; 730 1.108 dyoung callout_reset(&sc->sc_delay, hz / 50, ukbd_delayed_decode, sc); 731 1.74 lukem #ifdef DDB 732 1.109 phx } else if (sc->sc_console_keyboard && !(sc->sc_flags & FLAG_POLLING)) { 733 1.69 augustss /* 734 1.69 augustss * For the console keyboard we can't deliver CTL-ALT-ESC 735 1.69 augustss * from the interrupt routine. Doing so would start 736 1.69 augustss * polling from inside the interrupt routine and that 737 1.69 augustss * loses bigtime. 738 1.69 augustss */ 739 1.146 tih sc->sc_data_w = (sc->sc_data_w + 1) % MAXPENDING; 740 1.146 tih sc->sc_data[sc->sc_data_w] = *ud; 741 1.146 tih callout_reset(&sc->sc_delay, 0, ukbd_delayed_decode, sc); 742 1.69 augustss #endif 743 1.62 augustss } else { 744 1.62 augustss ukbd_decode(sc, ud); 745 1.62 augustss } 746 1.62 augustss } 747 1.62 augustss 748 1.153 jmcneill Static void 749 1.153 jmcneill ukbd_delayed_leds_off(void *addr) 750 1.153 jmcneill { 751 1.153 jmcneill struct ukbd_softc *sc = addr; 752 1.153 jmcneill 753 1.156 riastrad /* 754 1.156 riastrad * If the LEDs have already been set after attach, other than 755 1.156 riastrad * by our initial flashing of them, leave them be. 756 1.156 riastrad */ 757 1.156 riastrad if (sc->sc_leds_set) 758 1.156 riastrad return; 759 1.156 riastrad 760 1.153 jmcneill ukbd_set_leds(sc, 0); 761 1.153 jmcneill } 762 1.153 jmcneill 763 1.62 augustss void 764 1.62 augustss ukbd_delayed_decode(void *addr) 765 1.62 augustss { 766 1.62 augustss struct ukbd_softc *sc = addr; 767 1.62 augustss 768 1.146 tih while (sc->sc_data_r != sc->sc_data_w) { 769 1.146 tih sc->sc_data_r = (sc->sc_data_r + 1) % MAXPENDING; 770 1.146 tih ukbd_decode(sc, &sc->sc_data[sc->sc_data_r]); 771 1.146 tih } 772 1.62 augustss } 773 1.62 augustss 774 1.62 augustss void 775 1.62 augustss ukbd_decode(struct ukbd_softc *sc, struct ukbd_data *ud) 776 1.62 augustss { 777 1.131 skrll uint16_t ibuf[MAXKEYS]; /* chars events */ 778 1.62 augustss int s; 779 1.138 jakllsch int nkeys, i; 780 1.138 jakllsch #ifdef WSDISPLAY_COMPAT_RAWKBD 781 1.138 jakllsch int j; 782 1.138 jakllsch #endif 783 1.62 augustss int key; 784 1.135 maya #define ADDKEY(c) do { \ 785 1.135 maya KASSERT(nkeys < MAXKEYS); \ 786 1.135 maya ibuf[nkeys++] = (c); \ 787 1.135 maya } while (0) 788 1.62 augustss 789 1.62 augustss #ifdef UKBD_DEBUG 790 1.82 augustss /* 791 1.62 augustss * Keep a trace of the last events. Using printf changes the 792 1.62 augustss * timing, so this can be useful sometimes. 793 1.62 augustss */ 794 1.62 augustss if (ukbdtrace) { 795 1.62 augustss struct ukbdtraceinfo *p = &ukbdtracedata[ukbdtraceindex]; 796 1.159 riastrad p->unit = device_unit(sc->sc_dev); 797 1.62 augustss microtime(&p->tv); 798 1.62 augustss p->ud = *ud; 799 1.62 augustss if (++ukbdtraceindex >= UKBDTRACESIZE) 800 1.62 augustss ukbdtraceindex = 0; 801 1.62 augustss } 802 1.62 augustss if (ukbddebug > 5) { 803 1.62 augustss struct timeval tv; 804 1.62 augustss microtime(&tv); 805 1.138 jakllsch DPRINTF((" at %"PRIu64".%06"PRIu64":", tv.tv_sec, 806 1.138 jakllsch (uint64_t)tv.tv_usec)); 807 1.138 jakllsch for (size_t k = 0; k < MAXKEYS; k++) { 808 1.138 jakllsch if (isset(ud->keys, k)) 809 1.138 jakllsch DPRINTF((" %zu", k)); 810 1.138 jakllsch } 811 1.138 jakllsch DPRINTF((".\n")); 812 1.62 augustss } 813 1.62 augustss #endif 814 1.1 augustss 815 1.138 jakllsch if (isset(ud->keys, KEY_ERROR)) { 816 1.141 christos DPRINTF(("%s: KEY_ERROR\n", __func__)); 817 1.1 augustss return; /* ignore */ 818 1.53 augustss } 819 1.109 phx 820 1.109 phx if (sc->sc_flags & FLAG_APPLE_FIX_ISO) 821 1.109 phx ukbd_translate_keycodes(sc, ud, trtab_apple_iso); 822 1.109 phx 823 1.1 augustss nkeys = 0; 824 1.138 jakllsch for (i = 0; i < MAXKEYS; i++) { 825 1.113 macallan #ifdef GDIUM_KEYBOARD_HACK 826 1.138 jakllsch if (sc->sc_flags & FLAG_GDIUM_FN && i == 0x82) { 827 1.138 jakllsch if (isset(ud->keys, i)) 828 1.138 jakllsch sc->sc_flags |= FLAG_FN_PRESSED; 829 1.138 jakllsch else 830 1.111 macallan sc->sc_flags &= ~FLAG_FN_PRESSED; 831 1.111 macallan } 832 1.113 macallan #endif 833 1.138 jakllsch if (isset(ud->keys, i) != isset(sc->sc_odata.keys, i)) { 834 1.138 jakllsch key = i | ((isset(ud->keys, i) ? PRESS : RELEASE)); 835 1.138 jakllsch ADDKEY(ukbd_translate_modifier(sc, key)); 836 1.111 macallan } 837 1.1 augustss } 838 1.1 augustss sc->sc_odata = *ud; 839 1.1 augustss 840 1.20 augustss if (nkeys == 0) 841 1.20 augustss return; 842 1.20 augustss 843 1.109 phx if (sc->sc_flags & FLAG_POLLING) { 844 1.145 christos DPRINTFN(1,("%s: pollchar = 0x%03x\n", __func__, ibuf[0])); 845 1.131 skrll memcpy(sc->sc_pollchars, ibuf, nkeys * sizeof(uint16_t)); 846 1.23 augustss sc->sc_npollchar = nkeys; 847 1.3 augustss return; 848 1.3 augustss } 849 1.20 augustss #ifdef WSDISPLAY_COMPAT_RAWKBD 850 1.19 augustss if (sc->sc_rawkbd) { 851 1.79 augustss u_char cbuf[MAXKEYS * 2]; 852 1.24 augustss int c; 853 1.128 martin #if defined(UKBD_REPEAT) 854 1.128 martin int npress = 0; 855 1.128 martin #endif 856 1.20 augustss 857 1.128 martin for (i = j = 0; i < nkeys; i++) { 858 1.23 augustss key = ibuf[i]; 859 1.23 augustss c = ukbd_trtab[key & CODEMASK]; 860 1.23 augustss if (c == NN) 861 1.23 augustss continue; 862 1.104 jakllsch if (c == 0x7f) { 863 1.104 jakllsch /* pause key */ 864 1.104 jakllsch cbuf[j++] = 0xe1; 865 1.104 jakllsch cbuf[j++] = 0x1d; 866 1.104 jakllsch cbuf[j-1] |= (key & RELEASE) ? 0x80 : 0; 867 1.104 jakllsch cbuf[j] = 0x45; 868 1.104 jakllsch } else { 869 1.104 jakllsch if (c & 0x80) 870 1.104 jakllsch cbuf[j++] = 0xe0; 871 1.104 jakllsch cbuf[j] = c & 0x7f; 872 1.104 jakllsch } 873 1.23 augustss if (key & RELEASE) 874 1.19 augustss cbuf[j] |= 0x80; 875 1.87 augustss #if defined(UKBD_REPEAT) 876 1.20 augustss else { 877 1.23 augustss /* remember pressed keys for autorepeat */ 878 1.20 augustss if (c & 0x80) 879 1.20 augustss sc->sc_rep[npress++] = 0xe0; 880 1.20 augustss sc->sc_rep[npress++] = c & 0x7f; 881 1.20 augustss } 882 1.87 augustss #endif 883 1.145 christos DPRINTFN(1,("%s: raw = %s0x%02x\n", __func__, 884 1.27 augustss c & 0x80 ? "0xe0 " : "", 885 1.27 augustss cbuf[j])); 886 1.23 augustss j++; 887 1.19 augustss } 888 1.30 augustss s = spltty(); 889 1.19 augustss wskbd_rawinput(sc->sc_wskbddev, cbuf, j); 890 1.30 augustss splx(s); 891 1.87 augustss #ifdef UKBD_REPEAT 892 1.108 dyoung callout_stop(&sc->sc_rawrepeat_ch); 893 1.20 augustss if (npress != 0) { 894 1.20 augustss sc->sc_nrep = npress; 895 1.108 dyoung callout_reset(&sc->sc_rawrepeat_ch, 896 1.57 thorpej hz * REP_DELAY1 / 1000, ukbd_rawrepeat, sc); 897 1.20 augustss } 898 1.87 augustss #endif 899 1.19 augustss return; 900 1.19 augustss } 901 1.19 augustss #endif 902 1.19 augustss 903 1.30 augustss s = spltty(); 904 1.2 augustss for (i = 0; i < nkeys; i++) { 905 1.23 augustss key = ibuf[i]; 906 1.82 augustss wskbd_input(sc->sc_wskbddev, 907 1.23 augustss key&RELEASE ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN, 908 1.23 augustss key&CODEMASK); 909 1.20 augustss } 910 1.30 augustss splx(s); 911 1.1 augustss } 912 1.1 augustss 913 1.2 augustss void 914 1.60 augustss ukbd_set_leds(void *v, int leds) 915 1.1 augustss { 916 1.2 augustss struct ukbd_softc *sc = v; 917 1.158 riastrad struct usbd_device *udev = sc->sc_udev; 918 1.1 augustss 919 1.141 christos DPRINTF(("%s: sc=%p leds=%d, sc_leds=%d\n", __func__, 920 1.71 augustss sc, leds, sc->sc_leds)); 921 1.40 augustss 922 1.40 augustss if (sc->sc_dying) 923 1.40 augustss return; 924 1.1 augustss 925 1.156 riastrad sc->sc_leds_set = 1; 926 1.156 riastrad 927 1.71 augustss if (sc->sc_leds == leds) 928 1.71 augustss return; 929 1.129 skrll 930 1.2 augustss sc->sc_leds = leds; 931 1.129 skrll usb_add_task(udev, &sc->sc_ledtask, USB_TASKQ_DRIVER); 932 1.129 skrll } 933 1.129 skrll 934 1.129 skrll void 935 1.129 skrll ukbd_set_leds_task(void *v) 936 1.129 skrll { 937 1.129 skrll struct ukbd_softc *sc = v; 938 1.129 skrll int leds = sc->sc_leds; 939 1.129 skrll uint8_t res = 0; 940 1.129 skrll 941 1.75 augustss /* XXX not really right */ 942 1.121 khorben if ((leds & WSKBD_LED_COMPOSE) && sc->sc_compose.size == 1) 943 1.121 khorben res |= 1 << sc->sc_compose.pos; 944 1.75 augustss if ((leds & WSKBD_LED_SCROLL) && sc->sc_scroloc.size == 1) 945 1.75 augustss res |= 1 << sc->sc_scroloc.pos; 946 1.75 augustss if ((leds & WSKBD_LED_NUM) && sc->sc_numloc.size == 1) 947 1.75 augustss res |= 1 << sc->sc_numloc.pos; 948 1.75 augustss if ((leds & WSKBD_LED_CAPS) && sc->sc_capsloc.size == 1) 949 1.75 augustss res |= 1 << sc->sc_capsloc.pos; 950 1.129 skrll 951 1.159 riastrad uhidev_set_report(sc->sc_hdev, UHID_OUTPUT_REPORT, &res, 1); 952 1.1 augustss } 953 1.1 augustss 954 1.87 augustss #if defined(WSDISPLAY_COMPAT_RAWKBD) && defined(UKBD_REPEAT) 955 1.20 augustss void 956 1.60 augustss ukbd_rawrepeat(void *v) 957 1.20 augustss { 958 1.20 augustss struct ukbd_softc *sc = v; 959 1.30 augustss int s; 960 1.20 augustss 961 1.30 augustss s = spltty(); 962 1.20 augustss wskbd_rawinput(sc->sc_wskbddev, sc->sc_rep, sc->sc_nrep); 963 1.30 augustss splx(s); 964 1.108 dyoung callout_reset(&sc->sc_rawrepeat_ch, hz * REP_DELAYN / 1000, 965 1.57 thorpej ukbd_rawrepeat, sc); 966 1.20 augustss } 967 1.87 augustss #endif /* defined(WSDISPLAY_COMPAT_RAWKBD) && defined(UKBD_REPEAT) */ 968 1.20 augustss 969 1.1 augustss int 970 1.95 christos ukbd_ioctl(void *v, u_long cmd, void *data, int flag, 971 1.94 christos struct lwp *l) 972 1.1 augustss { 973 1.2 augustss struct ukbd_softc *sc = v; 974 1.1 augustss 975 1.2 augustss switch (cmd) { 976 1.2 augustss case WSKBDIO_GTYPE: 977 1.20 augustss *(int *)data = WSKBD_TYPE_USB; 978 1.131 skrll return 0; 979 1.2 augustss case WSKBDIO_SETLEDS: 980 1.2 augustss ukbd_set_leds(v, *(int *)data); 981 1.131 skrll return 0; 982 1.2 augustss case WSKBDIO_GETLEDS: 983 1.2 augustss *(int *)data = sc->sc_leds; 984 1.131 skrll return 0; 985 1.87 augustss #if defined(WSDISPLAY_COMPAT_RAWKBD) 986 1.2 augustss case WSKBDIO_SETMODE: 987 1.141 christos DPRINTF(("%s: set raw = %d\n", __func__, *(int *)data)); 988 1.2 augustss sc->sc_rawkbd = *(int *)data == WSKBD_RAW; 989 1.87 augustss #if defined(UKBD_REPEAT) 990 1.108 dyoung callout_stop(&sc->sc_rawrepeat_ch); 991 1.87 augustss #endif 992 1.131 skrll return 0; 993 1.2 augustss #endif 994 1.2 augustss } 995 1.131 skrll return EPASSTHROUGH; 996 1.1 augustss } 997 1.7 augustss 998 1.71 augustss /* 999 1.71 augustss * This is a hack to work around some broken ports that don't call 1000 1.71 augustss * cnpollc() before cngetc(). 1001 1.71 augustss */ 1002 1.71 augustss static int pollenter, warned; 1003 1.71 augustss 1004 1.7 augustss /* Console interface. */ 1005 1.3 augustss void 1006 1.60 augustss ukbd_cngetc(void *v, u_int *type, int *data) 1007 1.3 augustss { 1008 1.3 augustss struct ukbd_softc *sc = v; 1009 1.4 augustss int c; 1010 1.71 augustss int broken; 1011 1.71 augustss 1012 1.71 augustss if (pollenter == 0) { 1013 1.71 augustss if (!warned) { 1014 1.71 augustss printf("\n" 1015 1.71 augustss "This port is broken, it does not call cnpollc() before calling cngetc().\n" 1016 1.71 augustss "This should be fixed, but it will work anyway (for now).\n"); 1017 1.71 augustss warned = 1; 1018 1.71 augustss } 1019 1.71 augustss broken = 1; 1020 1.71 augustss ukbd_cnpollc(v, 1); 1021 1.71 augustss } else 1022 1.71 augustss broken = 0; 1023 1.3 augustss 1024 1.141 christos DPRINTFN(0,("%s: enter\n", __func__)); 1025 1.109 phx sc->sc_flags |= FLAG_POLLING; 1026 1.140 jmcneill if (sc->sc_npollchar <= 0) 1027 1.158 riastrad usbd_dopoll(sc->sc_iface); 1028 1.109 phx sc->sc_flags &= ~FLAG_POLLING; 1029 1.140 jmcneill if (sc->sc_npollchar > 0) { 1030 1.140 jmcneill c = sc->sc_pollchars[0]; 1031 1.140 jmcneill sc->sc_npollchar--; 1032 1.140 jmcneill memmove(sc->sc_pollchars, sc->sc_pollchars+1, 1033 1.140 jmcneill sc->sc_npollchar * sizeof(uint16_t)); 1034 1.140 jmcneill *type = c & RELEASE ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN; 1035 1.140 jmcneill *data = c & CODEMASK; 1036 1.145 christos DPRINTFN(0,("%s: return 0x%02x\n", __func__, c)); 1037 1.140 jmcneill } else { 1038 1.140 jmcneill *type = 0; 1039 1.140 jmcneill *data = 0; 1040 1.140 jmcneill } 1041 1.71 augustss if (broken) 1042 1.71 augustss ukbd_cnpollc(v, 0); 1043 1.3 augustss } 1044 1.3 augustss 1045 1.3 augustss void 1046 1.60 augustss ukbd_cnpollc(void *v, int on) 1047 1.3 augustss { 1048 1.6 augustss struct ukbd_softc *sc = v; 1049 1.131 skrll struct usbd_device *dev; 1050 1.6 augustss 1051 1.141 christos DPRINTFN(2,("%s: sc=%p on=%d\n", __func__, v, on)); 1052 1.6 augustss 1053 1.158 riastrad /* XXX Can this just use sc->sc_udev, or am I mistaken? */ 1054 1.158 riastrad usbd_interface2device_handle(sc->sc_iface, &dev); 1055 1.84 augustss if (on) { 1056 1.84 augustss sc->sc_spl = splusb(); 1057 1.84 augustss pollenter++; 1058 1.163 riastrad } 1059 1.163 riastrad usbd_set_polling(dev, on); 1060 1.163 riastrad if (!on) { 1061 1.163 riastrad pollenter--; 1062 1.84 augustss splx(sc->sc_spl); 1063 1.84 augustss } 1064 1.3 augustss } 1065 1.18 augustss 1066 1.18 augustss int 1067 1.60 augustss ukbd_cnattach(void) 1068 1.18 augustss { 1069 1.18 augustss 1070 1.31 thorpej /* 1071 1.31 thorpej * XXX USB requires too many parts of the kernel to be running 1072 1.31 thorpej * XXX in order to work, so we can't do much for the console 1073 1.155 andvar * XXX keyboard until autoconfiguration has run its course. 1074 1.31 thorpej */ 1075 1.31 thorpej ukbd_is_console = 1; 1076 1.131 skrll return 0; 1077 1.75 augustss } 1078 1.75 augustss 1079 1.75 augustss const char * 1080 1.75 augustss ukbd_parse_desc(struct ukbd_softc *sc) 1081 1.75 augustss { 1082 1.75 augustss struct hid_data *d; 1083 1.75 augustss struct hid_item h; 1084 1.75 augustss int size; 1085 1.75 augustss void *desc; 1086 1.138 jakllsch int ikey; 1087 1.75 augustss 1088 1.159 riastrad uhidev_get_report_desc(sc->sc_hdev, &desc, &size); 1089 1.138 jakllsch ikey = 0; 1090 1.75 augustss sc->sc_nkeycode = 0; 1091 1.75 augustss d = hid_start_parse(desc, size, hid_input); 1092 1.75 augustss while (hid_get_item(d, &h)) { 1093 1.109 phx /* Check for special Apple notebook FN key */ 1094 1.109 phx if (HID_GET_USAGE_PAGE(h.usage) == 0x00ff && 1095 1.109 phx HID_GET_USAGE(h.usage) == 0x0003 && 1096 1.109 phx h.kind == hid_input && (h.flags & HIO_VARIABLE)) { 1097 1.109 phx sc->sc_flags |= FLAG_APPLE_FN; 1098 1.109 phx sc->sc_apple_fn = h.loc; 1099 1.109 phx } 1100 1.109 phx 1101 1.75 augustss if (h.kind != hid_input || (h.flags & HIO_CONST) || 1102 1.75 augustss HID_GET_USAGE_PAGE(h.usage) != HUP_KEYBOARD || 1103 1.159 riastrad h.report_ID != sc->sc_report_id) 1104 1.75 augustss continue; 1105 1.144 christos DPRINTF(("%s: ikey=%d usage=%#x flags=%#x pos=%d size=%d " 1106 1.141 christos "cnt=%d\n", __func__, ikey, h.usage, h.flags, h.loc.pos, 1107 1.141 christos h.loc.size, h.loc.count)); 1108 1.75 augustss if (h.flags & HIO_VARIABLE) { 1109 1.137 jakllsch if (h.loc.size != 1) { 1110 1.137 jakllsch hid_end_parse(d); 1111 1.131 skrll return "bad modifier size"; 1112 1.137 jakllsch } 1113 1.75 augustss /* Single item */ 1114 1.138 jakllsch if (ikey < MAXKEYS) { 1115 1.138 jakllsch sc->sc_keyloc[ikey] = h.loc; 1116 1.138 jakllsch sc->sc_keyuse[ikey] = HID_GET_USAGE(h.usage); 1117 1.138 jakllsch ikey++; 1118 1.137 jakllsch } else { 1119 1.137 jakllsch hid_end_parse(d); 1120 1.138 jakllsch return "too many Variable keys"; 1121 1.137 jakllsch } 1122 1.75 augustss } else { 1123 1.75 augustss /* Array */ 1124 1.137 jakllsch if (h.loc.size != 8) { 1125 1.137 jakllsch hid_end_parse(d); 1126 1.131 skrll return "key code size != 8"; 1127 1.137 jakllsch } 1128 1.75 augustss if (h.loc.count > MAXKEYCODE) 1129 1.110 mbalmer h.loc.count = MAXKEYCODE; 1130 1.137 jakllsch if (h.loc.pos % 8 != 0) { 1131 1.137 jakllsch hid_end_parse(d); 1132 1.131 skrll return "key codes not on byte boundary"; 1133 1.137 jakllsch } 1134 1.137 jakllsch if (sc->sc_nkeycode != 0) { 1135 1.137 jakllsch hid_end_parse(d); 1136 1.131 skrll return "multiple key code arrays"; 1137 1.137 jakllsch } 1138 1.75 augustss sc->sc_keycodeloc = h.loc; 1139 1.75 augustss sc->sc_nkeycode = h.loc.count; 1140 1.75 augustss } 1141 1.75 augustss } 1142 1.138 jakllsch sc->sc_nkeyloc = ikey; 1143 1.75 augustss hid_end_parse(d); 1144 1.75 augustss 1145 1.75 augustss hid_locate(desc, size, HID_USAGE2(HUP_LEDS, HUD_LED_NUM_LOCK), 1146 1.159 riastrad sc->sc_report_id, hid_output, &sc->sc_numloc, NULL); 1147 1.75 augustss hid_locate(desc, size, HID_USAGE2(HUP_LEDS, HUD_LED_CAPS_LOCK), 1148 1.159 riastrad sc->sc_report_id, hid_output, &sc->sc_capsloc, NULL); 1149 1.75 augustss hid_locate(desc, size, HID_USAGE2(HUP_LEDS, HUD_LED_SCROLL_LOCK), 1150 1.159 riastrad sc->sc_report_id, hid_output, &sc->sc_scroloc, NULL); 1151 1.121 khorben hid_locate(desc, size, HID_USAGE2(HUP_LEDS, HUD_LED_COMPOSE), 1152 1.159 riastrad sc->sc_report_id, hid_output, &sc->sc_compose, NULL); 1153 1.75 augustss 1154 1.131 skrll return NULL; 1155 1.18 augustss } 1156