1 /* $OpenBSD: ucc.c,v 1.28 2021/11/17 06:21:23 anton Exp $ */ 2 3 /* 4 * Copyright (c) 2021 Anton Lindqvist <anton@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/systm.h> 21 #include <sys/device.h> 22 #include <sys/malloc.h> 23 24 #include <dev/usb/usb.h> 25 #include <dev/usb/usbhid.h> 26 #include <dev/usb/usbdi.h> 27 #include <dev/usb/uhidev.h> 28 29 #include <dev/wscons/wsconsio.h> 30 #include <dev/wscons/wskbdvar.h> 31 #include <dev/wscons/wsksymdef.h> 32 #include <dev/wscons/wsksymvar.h> 33 34 /* #define UCC_DEBUG */ 35 #ifdef UCC_DEBUG 36 #define DPRINTF(x...) do { if (ucc_debug) printf(x); } while (0) 37 void ucc_dump(const char *, uint8_t *, u_int); 38 int ucc_debug = 1; 39 #else 40 #define DPRINTF(x...) 41 #define ucc_dump(prefix, data, len) 42 #endif 43 44 struct ucc_softc { 45 struct uhidev sc_hdev; 46 struct device *sc_wskbddev; 47 48 /* Key mappings used in translating mode. */ 49 keysym_t *sc_map; 50 u_int sc_maplen; 51 u_int sc_mapsiz; 52 53 /* Key mappings used in raw mode. */ 54 const struct ucc_keysym **sc_raw; 55 u_int sc_rawsiz; 56 57 u_int sc_nusages; 58 int sc_isarray; 59 int sc_mode; 60 61 /* 62 * Slice of the interrupt buffer which represents a pressed key. 63 * See section 8 (Report Protocol) of the HID specification v1.11. 64 */ 65 struct { 66 uint8_t *i_buf; 67 uint32_t i_bufsiz; 68 uint32_t i_off; /* offset in bits */ 69 uint32_t i_len; /* length in bits */ 70 } sc_input; 71 72 struct { 73 uint32_t v_inc; /* volume increment bit offset */ 74 uint32_t v_dec; /* volume decrement bit offset */ 75 uint32_t v_off; /* offset in bits */ 76 uint32_t v_len; /* length in bits */ 77 } sc_volume; 78 79 /* Last pressed key. */ 80 union { 81 int sc_last_translate; 82 u_char sc_last_raw; 83 }; 84 85 /* 86 * Only the first element is populated whereas the second remains zeroed 87 * out since such trailing sentinel is required by wskbd_load_keymap(). 88 */ 89 struct wscons_keydesc sc_keydesc[2]; 90 struct wskbd_mapdata sc_keymap; 91 }; 92 93 struct ucc_keysym { 94 #ifdef UCC_DEBUG 95 const char *us_name; 96 #endif 97 int32_t us_usage; 98 keysym_t us_key; 99 u_char us_raw; 100 }; 101 102 int ucc_match(struct device *, void *, void *); 103 void ucc_attach(struct device *, struct device *, void *); 104 int ucc_detach(struct device *, int); 105 void ucc_intr(struct uhidev *, void *, u_int); 106 107 void ucc_attach_wskbd(struct ucc_softc *); 108 int ucc_enable(void *, int); 109 void ucc_set_leds(void *, int); 110 int ucc_ioctl(void *, u_long, caddr_t, int, struct proc *); 111 112 int ucc_hid_match(void *, int, uint8_t); 113 int ucc_hid_parse(struct ucc_softc *, void *, int); 114 int ucc_hid_parse_array(struct ucc_softc *, const struct hid_item *); 115 int ucc_hid_is_array(const struct hid_item *); 116 int ucc_add_key(struct ucc_softc *, int32_t, u_int); 117 int ucc_add_key_volume(struct ucc_softc *, const struct hid_item *, 118 uint32_t, u_int); 119 int ucc_bit_to_sym(struct ucc_softc *, u_int, const struct ucc_keysym **); 120 int ucc_usage_to_sym(int32_t, const struct ucc_keysym **); 121 int ucc_bits_to_int(uint8_t *, u_int, int32_t *); 122 int ucc_bits_to_volume(struct ucc_softc *, uint8_t *, int, u_int *); 123 int ucc_intr_slice(struct ucc_softc *, uint8_t *, uint8_t *, int *); 124 void ucc_input(struct ucc_softc *, u_int, int); 125 void ucc_rawinput(struct ucc_softc *, u_char, int); 126 int ucc_setbits(struct ucc_softc *, uint8_t *, int, u_int *); 127 128 struct cfdriver ucc_cd = { 129 NULL, "ucc", DV_DULL 130 }; 131 132 const struct cfattach ucc_ca = { 133 sizeof(struct ucc_softc), 134 ucc_match, 135 ucc_attach, 136 ucc_detach, 137 }; 138 139 /* 140 * Mapping of HID Consumer Control usages to key symbols based on the HID Usage 141 * Tables 1.21 specification. The same usages can also be found at 142 * /usr/share/misc/usb_hid_usages. 143 * The raw scan codes are taken from X11, see the media_nav_acpi_common symbols 144 * in dist/xkeyboard-config/symbols/inet. 145 * Then use dist/xkeyboard-config/keycodes/xfree86 to resolve keys to the 146 * corresponding raw scan code. 147 */ 148 static const struct ucc_keysym ucc_keysyms[] = { 149 #ifdef UCC_DEBUG 150 #define Y(usage, name, key, raw) { name, usage, key, raw }, 151 #else 152 #define Y(usage, name, key, raw) { usage, key, raw }, 153 #endif 154 #define N(usage, name, key, raw) 155 /* 0x0000 Unassigned */ 156 N(0x0001, "Consumer Control", 0, 0) 157 N(0x0002, "Numeric Key Pad", 0, 0) 158 N(0x0003, "Programmable Buttons", 0, 0) 159 N(0x0004, "Microphone", 0, 0) 160 N(0x0005, "Headphone", 0, 0) 161 N(0x0006, "Graphic Equalizer", 0, 0) 162 /* 0x0007-0x001F Reserved */ 163 N(0x0020, "+10", 0, 0) 164 N(0x0021, "+100", 0, 0) 165 N(0x0022, "AM/PM", 0, 0) 166 /* 0x0023-0x002F Reserved */ 167 Y(0x0030, "Power", 0, 222 /* I5E = XF86PowerOff */) 168 N(0x0031, "Reset", 0, 0) 169 Y(0x0032, "Sleep", 0, 150 /* I16 = XF86Sleep */) 170 N(0x0033, "Sleep After", 0, 0) 171 N(0x0034, "Sleep Mode", 0, 0) 172 N(0x0035, "Illumination", 0, 0) 173 N(0x0036, "Function Buttons", 0, 0) 174 /* 0x0037-0x003F Reserved */ 175 N(0x0040, "Menu", 0, 0) 176 N(0x0041, "Menu Pick", 0, 0) 177 N(0x0042, "Menu Up", 0, 0) 178 N(0x0043, "Menu Down", 0, 0) 179 N(0x0044, "Menu Left", 0, 0) 180 N(0x0045, "Menu Right", 0, 0) 181 N(0x0046, "Menu Escape", 0, 0) 182 N(0x0047, "Menu Value Increase", 0, 0) 183 N(0x0048, "Menu Value Decrease", 0, 0) 184 /* 0x0049-0x005F Reserved */ 185 N(0x0060, "Data On Screen", 0, 0) 186 N(0x0061, "Closed Caption", 0, 0) 187 N(0x0062, "Closed Caption Select", 0, 0) 188 N(0x0063, "VCR/TV", 0, 0) 189 N(0x0064, "Broadcast Mode", 0, 0) 190 N(0x0065, "Snapshot", 0, 0) 191 N(0x0066, "Still", 0, 0) 192 N(0x0067, "Picture-in-Picture Toggle", 0, 0) 193 N(0x0068, "Picture-in-Picture Swap", 0, 0) 194 N(0x0069, "Red Menu Button", 0, 0) 195 N(0x006A, "Green Menu Button", 0, 0) 196 N(0x006B, "Blue Menu Button", 0, 0) 197 N(0x006C, "Yellow Menu Button", 0, 0) 198 N(0x006D, "Aspect", 0, 0) 199 N(0x006E, "3D Mode Select", 0, 0) 200 N(0x006F, "Display Brightness Increment", 0, 0) 201 N(0x0070, "Display Brightness Decrement", 0, 0) 202 N(0x0071, "Display Brightness", 0, 0) 203 N(0x0072, "Display Backlight Toggle", 0, 0) 204 N(0x0073, "Display Set Brightness to Minimum", 0, 0) 205 N(0x0074, "Display Set Brightness to Maximum", 0, 0) 206 N(0x0075, "Display Set Auto Brightness", 0, 0) 207 N(0x0076, "Camera Access Enabled", 0, 0) 208 N(0x0077, "Camera Access Disabled", 0, 0) 209 N(0x0078, "Camera Access Toggle", 0, 0) 210 N(0x0079, "Keyboard Brightness Increment", 0, 0) 211 N(0x007A, "Keyboard Brightness Decrement", 0, 0) 212 N(0x007B, "Keyboard Backlight Set Level", 0, 0) 213 N(0x007C, "Keyboard Backlight OOC", 0, 0) 214 N(0x007D, "Keyboard Backlight Set Minimum", 0, 0) 215 N(0x007E, "Keyboard Backlight Set Maximum", 0, 0) 216 N(0x007F, "Keyboard Backlight Auto", 0, 0) 217 N(0x0080, "Selection", 0, 0) 218 N(0x0081, "Assign Selection", 0, 0) 219 N(0x0082, "Mode Step", 0, 0) 220 N(0x0083, "Recall Last", 0, 0) 221 N(0x0084, "Enter Channel", 0, 0) 222 N(0x0085, "Order Movie", 0, 0) 223 N(0x0086, "Channel", 0, 0) 224 N(0x0087, "Media Selection", 0, 0) 225 N(0x0088, "Media Select Computer", 0, 0) 226 N(0x0089, "Media Select TV", 0, 0) 227 N(0x008A, "Media Select WWW", 0, 0) 228 N(0x008B, "Media Select DVD", 0, 0) 229 N(0x008C, "Media Select Telephone", 0, 0) 230 N(0x008D, "Media Select Program Guide", 0, 0) 231 N(0x008E, "Media Select Video Phone", 0, 0) 232 N(0x008F, "Media Select Games", 0, 0) 233 N(0x0090, "Media Select Messages", 0, 0) 234 N(0x0091, "Media Select CD", 0, 0) 235 N(0x0092, "Media Select VCR", 0, 0) 236 N(0x0093, "Media Select Tuner", 0, 0) 237 N(0x0094, "Quit", 0, 0) 238 N(0x0095, "Help", 0, 0) 239 N(0x0096, "Media Select Tape", 0, 0) 240 N(0x0097, "Media Select Cable", 0, 0) 241 N(0x0098, "Media Select Satellite", 0, 0) 242 N(0x0099, "Media Select Security", 0, 0) 243 N(0x009A, "Media Select Home", 0, 0) 244 N(0x009B, "Media Select Call", 0, 0) 245 N(0x009C, "Channel Increment", 0, 0) 246 N(0x009D, "Channel Decrement", 0, 0) 247 N(0x009E, "Media Select SAP", 0, 0) 248 /* 0x009F-0x009F Reserved */ 249 N(0x00A0, "VCR Plus", 0, 0) 250 N(0x00A1, "Once", 0, 0) 251 N(0x00A2, "Daily", 0, 0) 252 N(0x00A3, "Weekly", 0, 0) 253 N(0x00A4, "Monthly", 0, 0) 254 /* 0x00A5-0x00AF Reserved */ 255 N(0x00B0, "Play", 0, 0) 256 N(0x00B1, "Pause", 0, 0) 257 N(0x00B2, "Record", 0, 0) 258 N(0x00B3, "Fast Forward", 0, 0) 259 N(0x00B4, "Rewind", 0, 0) 260 Y(0x00B5, "Scan Next Track", 0, 153 /* I19 = XF86AudioNext */) 261 Y(0x00B6, "Scan Previous Track", 0, 144 /* I10 = XF86AudioPrev */) 262 Y(0x00B7, "Stop", 0, 164 /* I24 = XF86AudioStop */) 263 Y(0x00B8, "Eject", 0, 170 /* K5A = XF86Eject */) 264 N(0x00B9, "Random Play", 0, 0) 265 N(0x00BA, "Select Disc", 0, 0) 266 N(0x00BB, "Enter Disc", 0, 0) 267 N(0x00BC, "Repeat", 0, 0) 268 N(0x00BD, "Tracking", 0, 0) 269 N(0x00BE, "Track Normal", 0, 0) 270 N(0x00BF, "Slow Tracking", 0, 0) 271 N(0x00C0, "Frame Forward", 0, 0) 272 N(0x00C1, "Frame Back", 0, 0) 273 N(0x00C2, "Mark", 0, 0) 274 N(0x00C3, "Clear Mark", 0, 0) 275 N(0x00C4, "Repeat From Mark", 0, 0) 276 N(0x00C5, "Return To Mark", 0, 0) 277 N(0x00C6, "Search Mark Forward", 0, 0) 278 N(0x00C7, "Search Mark Backwards", 0, 0) 279 N(0x00C8, "Counter Reset", 0, 0) 280 N(0x00C9, "Show Counter", 0, 0) 281 N(0x00CA, "Tracking Increment", 0, 0) 282 N(0x00CB, "Tracking Decrement", 0, 0) 283 N(0x00CC, "Stop/Eject", 0, 0) 284 Y(0x00CD, "Play/Pause", 0, 162 /* I22 = XF86AudioPlay */) 285 N(0x00CE, "Play/Skip", 0, 0) 286 N(0x00CF, "Voice Command", 0, 0) 287 N(0x00D0, "Invoke Capture Interface", 0, 0) 288 N(0x00D1, "Start or Stop Game Recording", 0, 0) 289 N(0x00D2, "Historical Game Capture", 0, 0) 290 N(0x00D3, "Capture Game Screenshot", 0, 0) 291 N(0x00D4, "Show or Hide Recording Indicator", 0, 0) 292 N(0x00D5, "Start or Stop Microphone Capture", 0, 0) 293 N(0x00D6, "Start or Stop Camera Capture", 0, 0) 294 N(0x00D7, "Start or Stop Game Broadcast", 0, 0) 295 /* 0x00D8-0x00DF Reserved */ 296 N(0x00E0, "Volume", 0, 0) 297 N(0x00E1, "Balance", 0, 0) 298 Y(0x00E2, "Mute", KS_AudioMute, 160 /* I20 = XF86AudioMute */) 299 N(0x00E3, "Bass", 0, 0) 300 N(0x00E4, "Treble", 0, 0) 301 N(0x00E5, "Bass Boost", 0, 0) 302 N(0x00E6, "Surround Mode", 0, 0) 303 N(0x00E7, "Loudness", 0, 0) 304 N(0x00E8, "MPX", 0, 0) 305 Y(0x00E9, "Volume Increment", KS_AudioRaise, 176 /* I30 = XF86AudioRaiseVolume */) 306 Y(0x00EA, "Volume Decrement", KS_AudioLower, 174 /* I2E = XF86AudioLowerVolume */) 307 /* 0x00EB-0x00EF Reserved */ 308 N(0x00F0, "Speed Select", 0, 0) 309 N(0x00F1, "Playback Speed", 0, 0) 310 N(0x00F2, "Standard Play", 0, 0) 311 N(0x00F3, "Long Play", 0, 0) 312 N(0x00F4, "Extended Play", 0, 0) 313 N(0x00F5, "Slow", 0, 0) 314 /* 0x00F6-0x00FF Reserved */ 315 N(0x0100, "Fan Enable", 0, 0) 316 N(0x0101, "Fan Speed", 0, 0) 317 N(0x0102, "Light Enable", 0, 0) 318 N(0x0103, "Light Illumination Level", 0, 0) 319 N(0x0104, "Climate Control Enable", 0, 0) 320 N(0x0105, "Room Temperature", 0, 0) 321 N(0x0106, "Security Enable", 0, 0) 322 N(0x0107, "Fire Alarm", 0, 0) 323 N(0x0108, "Police Alarm", 0, 0) 324 N(0x0109, "Proximity", 0, 0) 325 N(0x010A, "Motion", 0, 0) 326 N(0x010B, "Duress Alarm", 0, 0) 327 N(0x010C, "Holdup Alarm", 0, 0) 328 N(0x010D, "Medical Alarm", 0, 0) 329 /* 0x010E-0x014F Reserved */ 330 N(0x0150, "Balance Right", 0, 0) 331 N(0x0151, "Balance Left", 0, 0) 332 N(0x0152, "Bass Increment", 0, 0) 333 N(0x0153, "Bass Decrement", 0, 0) 334 N(0x0154, "Treble Increment", 0, 0) 335 N(0x0155, "Treble Decrement", 0, 0) 336 /* 0x0156-0x015F Reserved */ 337 N(0x0160, "Speaker System", 0, 0) 338 N(0x0161, "Channel Left", 0, 0) 339 N(0x0162, "Channel Right", 0, 0) 340 N(0x0163, "Channel Center", 0, 0) 341 N(0x0164, "Channel Front", 0, 0) 342 N(0x0165, "Channel Center Front", 0, 0) 343 N(0x0166, "Channel Side", 0, 0) 344 N(0x0167, "Channel Surround", 0, 0) 345 N(0x0168, "Channel Low Frequency Enhancement", 0, 0) 346 N(0x0169, "Channel Top", 0, 0) 347 N(0x016A, "Channel Unknown", 0, 0) 348 /* 0x016B-0x016F Reserved */ 349 N(0x0170, "Sub-channel", 0, 0) 350 N(0x0171, "Sub-channel Increment", 0, 0) 351 N(0x0172, "Sub-channel Decrement", 0, 0) 352 N(0x0173, "Alternate Audio Increment", 0, 0) 353 N(0x0174, "Alternate Audio Decrement", 0, 0) 354 /* 0x0175-0x017F Reserved */ 355 N(0x0180, "Application Launch Buttons", 0, 0) 356 N(0x0181, "AL Launch Button Configuration Tool", 0, 0) 357 N(0x0182, "AL Programmable Button Configuration", 0, 0) 358 N(0x0183, "AL Consumer Control Configuration", 0, 0) 359 N(0x0184, "AL Word Processor", 0, 0) 360 N(0x0185, "AL Text Editor", 0, 0) 361 N(0x0186, "AL Spreadsheet", 0, 0) 362 N(0x0187, "AL Graphics Editor", 0, 0) 363 N(0x0188, "AL Presentation App", 0, 0) 364 N(0x0189, "AL Database App", 0, 0) 365 Y(0x018A, "AL Email Reader", 0, 235 /* I6C = XF86Mail */) 366 N(0x018B, "AL Newsreader", 0, 0) 367 N(0x018C, "AL Voicemail", 0, 0) 368 N(0x018D, "AL Contacts/Address Book", 0, 0) 369 N(0x018E, "AL Calendar/Schedule", 0, 0) 370 N(0x018F, "AL Task/Project Manager", 0, 0) 371 N(0x0190, "AL Log/Journal/Timecard", 0, 0) 372 N(0x0191, "AL Checkbook/Finance", 0, 0) 373 Y(0x0192, "AL Calculator", 0, 161 /* I21 = XF86Calculator */) 374 N(0x0193, "AL A/V Capture/Playback", 0, 0) 375 N(0x0194, "AL Local Machine Browser", 0, 0) 376 N(0x0195, "AL LAN/WAN Browser", 0, 0) 377 Y(0x0196, "AL Internet Browser", 0, 178 /* I32 = XF86WWW */) 378 N(0x0197, "AL Remote Networking/ISP Connect", 0, 0) 379 N(0x0198, "AL Network Conference", 0, 0) 380 N(0x0199, "AL Network Chat", 0, 0) 381 N(0x019A, "AL Telephony/Dialer", 0, 0) 382 N(0x019B, "AL Logon", 0, 0) 383 N(0x019C, "AL Logoff", 0, 0) 384 N(0x019D, "AL Logon/Logoff", 0, 0) 385 N(0x019E, "AL Terminal Lock/Screensaver", 0, 0) 386 N(0x019F, "AL Control Panel", 0, 0) 387 N(0x01A0, "AL Command Line Processor/Run", 0, 0) 388 N(0x01A1, "AL Process/Task Manager", 0, 0) 389 N(0x01A2, "AL Select Tast/Application", 0, 0) 390 N(0x01A3, "AL Next Task/Application", 0, 0) 391 N(0x01A4, "AL Previous Task/Application", 0, 0) 392 N(0x01A5, "AL Preemptive Halt Task/Application", 0, 0) 393 N(0x01A6, "AL Integrated Help Center", 0, 0) 394 N(0x01A7, "AL My Documents", 0, 0) 395 N(0x01A8, "AL Thesaurus", 0, 0) 396 N(0x01A9, "AL Dictionary", 0, 0) 397 N(0x01AA, "AL Desktop", 0, 0) 398 N(0x01AB, "AC Spell", 0, 0) 399 N(0x01AC, "AL Grammar Check", 0, 0) 400 N(0x01AD, "AL Wireless Status", 0, 0) 401 N(0x01AE, "AL Keyboard Layout", 0, 0) 402 N(0x01AF, "AL Virus Protection", 0, 0) 403 N(0x01B0, "AL Encryption", 0, 0) 404 N(0x01B1, "AL Screen Saver", 0, 0) 405 N(0x01B2, "AL Alarms", 0, 0) 406 N(0x01B3, "AL Clock", 0, 0) 407 N(0x01B4, "AL File Browser", 0, 0) 408 N(0x01B5, "AL Power Status", 0, 0) 409 N(0x01B6, "AL My Pictures", 0, 0) 410 N(0x01B7, "AL My Music", 0, 0) 411 N(0x01B8, "AL Movie Browser", 0, 0) 412 N(0x01B9, "AL Digital Rights Manager", 0, 0) 413 N(0x01BA, "AL Digital Wallet", 0, 0) 414 /* 0x01BB-0x01BB Reserved */ 415 N(0x01BC, "AL Instant Messaging", 0, 0) 416 N(0x01BD, "AL OEM Feature/Tips/Tutorial Browser", 0, 0) 417 N(0x01BE, "AL OEM Help", 0, 0) 418 N(0x01BF, "AL Online Community", 0, 0) 419 N(0x01C0, "AL Entertainment Content Browser", 0, 0) 420 N(0x01C1, "AL Online Shopping Browser", 0, 0) 421 N(0x01C2, "AL SmartCard Information/Help", 0, 0) 422 N(0x01C3, "AL Market Monitor/Finance Browser", 0, 0) 423 N(0x01C4, "AL Customized Corporate News Browser", 0, 0) 424 N(0x01C5, "AL Online Activity Browser", 0, 0) 425 Y(0x01C6, "AL Research/Search Browser", 0, 229 /* I65 = XF86Search */) 426 N(0x01C7, "AL Audio Player", 0, 0) 427 N(0x01C8, "AL Message Status", 0, 0) 428 N(0x01C9, "AL Contact Sync", 0, 0) 429 N(0x01CA, "AL Navigation", 0, 0) 430 N(0x01CB, "AL Context-aware Desktop Assistant", 0, 0) 431 /* 0x01CC-0x01FF Reserved */ 432 N(0x0200, "Generic GUI Application Controls", 0, 0) 433 N(0x0201, "AC New", 0, 0) 434 N(0x0202, "AC Open", 0, 0) 435 N(0x0203, "AC Close", 0, 0) 436 N(0x0204, "AC Exit", 0, 0) 437 N(0x0205, "AC Maximize", 0, 0) 438 N(0x0206, "AC Minimize", 0, 0) 439 N(0x0207, "AC Save", 0, 0) 440 N(0x0208, "AC Print", 0, 0) 441 N(0x0209, "AC Properties", 0, 0) 442 /* 0x020A-0x0219 Reserved */ 443 N(0x021A, "AC Undo", 0, 0) 444 N(0x021B, "AC Copy", 0, 0) 445 N(0x021C, "AC Cut", 0, 0) 446 N(0x021D, "AC Paste", 0, 0) 447 N(0x021E, "AC Select All", 0, 0) 448 N(0x021F, "AC Find", 0, 0) 449 N(0x0220, "AC Find and Replace", 0, 0) 450 N(0x0221, "AC Search", 0, 0) 451 N(0x0222, "AC Go To", 0, 0) 452 N(0x0223, "AC Home", 0, 0) 453 Y(0x0224, "AC Back", 0, 234 /* I6A = XF86Back */) 454 Y(0x0225, "AC Forward", 0, 233 /* I69 = XF86Forward */) 455 Y(0x0226, "AC Stop", 0, 232 /* I68 = XF86Stop */) 456 Y(0x0227, "AC Refresh", 0, 231 /* I67 = XF86Reload */) 457 N(0x0228, "AC Previous Link", 0, 0) 458 N(0x0229, "AC Next Link", 0, 0) 459 N(0x022A, "AC Bookmarks", 0, 0) 460 N(0x022B, "AC History", 0, 0) 461 N(0x022C, "AC Subscriptions", 0, 0) 462 N(0x022D, "AC Zoom In", 0, 0) 463 N(0x022E, "AC Zoom Out", 0, 0) 464 N(0x022F, "AC Zoom", 0, 0) 465 N(0x0230, "AC Full Screen View", 0, 0) 466 N(0x0231, "AC Normal View", 0, 0) 467 N(0x0232, "AC View Toggle", 0, 0) 468 N(0x0233, "AC Scroll Up", 0, 0) 469 N(0x0234, "AC Scroll Down", 0, 0) 470 N(0x0235, "AC Scroll", 0, 0) 471 N(0x0236, "AC Pan Left", 0, 0) 472 N(0x0237, "AC Pan Right", 0, 0) 473 N(0x0238, "AC Pan", 0, 0) 474 N(0x0239, "AC New Window", 0, 0) 475 N(0x023A, "AC Tile Horizontally", 0, 0) 476 N(0x023B, "AC Tile Vertically", 0, 0) 477 N(0x023C, "AC Format", 0, 0) 478 N(0x023D, "AC Edit", 0, 0) 479 N(0x023E, "AC Bold", 0, 0) 480 N(0x023F, "AC Italics", 0, 0) 481 N(0x0240, "AC Underline", 0, 0) 482 N(0x0241, "AC Strikethrough", 0, 0) 483 N(0x0242, "AC Subscript", 0, 0) 484 N(0x0243, "AC Superscript", 0, 0) 485 N(0x0244, "AC All Caps", 0, 0) 486 N(0x0245, "AC Rotate", 0, 0) 487 N(0x0246, "AC Resize", 0, 0) 488 N(0x0247, "AC Flip Horizontal", 0, 0) 489 N(0x0248, "AC Flip Vertical", 0, 0) 490 N(0x0249, "AC Mirror Horizontal", 0, 0) 491 N(0x024A, "AC Mirror Vertical", 0, 0) 492 N(0x024B, "AC Font Select", 0, 0) 493 N(0x024C, "AC Font Color", 0, 0) 494 N(0x024D, "AC Font Size", 0, 0) 495 N(0x024E, "AC Justify Left", 0, 0) 496 N(0x024F, "AC Justify Center H", 0, 0) 497 N(0x0250, "AC Justify Right", 0, 0) 498 N(0x0251, "AC Justify Block H", 0, 0) 499 N(0x0252, "AC Justify Top", 0, 0) 500 N(0x0253, "AC Justify Center V", 0, 0) 501 N(0x0254, "AC Justify Bottom", 0, 0) 502 N(0x0255, "AC Justify Block V", 0, 0) 503 N(0x0256, "AC Justify Decrease", 0, 0) 504 N(0x0257, "AC Justify Increase", 0, 0) 505 N(0x0258, "AC Numbered List", 0, 0) 506 N(0x0259, "AC Restart Numbering", 0, 0) 507 N(0x025A, "AC Bulleted List", 0, 0) 508 N(0x025B, "AC Promote", 0, 0) 509 N(0x025C, "AC Demote", 0, 0) 510 N(0x025D, "AC Yes", 0, 0) 511 N(0x025E, "AC No", 0, 0) 512 N(0x025F, "AC Cancel", 0, 0) 513 N(0x0260, "AC Catalog", 0, 0) 514 N(0x0261, "AC Buy/Checkout", 0, 0) 515 N(0x0262, "AC Add to Cart", 0, 0) 516 N(0x0263, "AC Expand", 0, 0) 517 N(0x0264, "AC Expand All", 0, 0) 518 N(0x0265, "AC Collapse", 0, 0) 519 N(0x0266, "AC Collapse All", 0, 0) 520 N(0x0267, "AC Print Preview", 0, 0) 521 N(0x0268, "AC Paste Special", 0, 0) 522 N(0x0269, "AC Insert Mode", 0, 0) 523 N(0x026A, "AC Delete", 0, 0) 524 N(0x026B, "AC Lock", 0, 0) 525 N(0x026C, "AC Unlock", 0, 0) 526 N(0x026D, "AC Protect", 0, 0) 527 N(0x026E, "AC Unprotect", 0, 0) 528 N(0x026F, "AC Attach Comment", 0, 0) 529 N(0x0270, "AC Delete Comment", 0, 0) 530 N(0x0271, "AC View Comment", 0, 0) 531 N(0x0272, "AC Select Word", 0, 0) 532 N(0x0273, "AC Select Sentence", 0, 0) 533 N(0x0274, "AC Select Paragraph", 0, 0) 534 N(0x0275, "AC Select Column", 0, 0) 535 N(0x0276, "AC Select Row", 0, 0) 536 N(0x0277, "AC Select Table", 0, 0) 537 N(0x0278, "AC Select Object", 0, 0) 538 N(0x0279, "AC Redo/Repeat", 0, 0) 539 N(0x027A, "AC Sort", 0, 0) 540 N(0x027B, "AC Sort Ascending", 0, 0) 541 N(0x027C, "AC Sort Descending", 0, 0) 542 N(0x027D, "AC Filter", 0, 0) 543 N(0x027E, "AC Set Clock", 0, 0) 544 N(0x027F, "AC View Clock", 0, 0) 545 N(0x0280, "AC Select Time Zone", 0, 0) 546 N(0x0281, "AC Edit Time Zones", 0, 0) 547 N(0x0282, "AC Set Alarm", 0, 0) 548 N(0x0283, "AC Clear Alarm", 0, 0) 549 N(0x0284, "AC Snooze Alarm", 0, 0) 550 N(0x0285, "AC Reset Alarm", 0, 0) 551 N(0x0286, "AC Synchronize", 0, 0) 552 N(0x0287, "AC Send/Receive", 0, 0) 553 N(0x0288, "AC Send To", 0, 0) 554 N(0x0289, "AC Reply", 0, 0) 555 N(0x028A, "AC Reply All", 0, 0) 556 N(0x028B, "AC Forward Message", 0, 0) 557 N(0x028C, "AC Send", 0, 0) 558 N(0x028D, "AC Attach File", 0, 0) 559 N(0x028E, "AC Upload", 0, 0) 560 N(0x028F, "AC Download (Save Target As)", 0, 0) 561 N(0x0290, "AC Set Borders", 0, 0) 562 N(0x0291, "AC Insert Row", 0, 0) 563 N(0x0292, "AC Insert Column", 0, 0) 564 N(0x0293, "AC Insert File", 0, 0) 565 N(0x0294, "AC Insert Picture", 0, 0) 566 N(0x0295, "AC Insert Object", 0, 0) 567 N(0x0296, "AC Insert Symbol", 0, 0) 568 N(0x0297, "AC Save and Close", 0, 0) 569 N(0x0298, "AC Rename", 0, 0) 570 N(0x0299, "AC Merge", 0, 0) 571 N(0x029A, "AC Split", 0, 0) 572 N(0x029B, "AC Distribute Horizontally", 0, 0) 573 N(0x029C, "AC Distribute Vertically", 0, 0) 574 N(0x029D, "AC Next Keyboard Layout Select", 0, 0) 575 N(0x029E, "AC Navigation Guidance", 0, 0) 576 N(0x029F, "AC Desktop Show All Windows", 0, 0) 577 N(0x02A0, "AC Soft Key Left", 0, 0) 578 N(0x02A1, "AC Soft Key Right", 0, 0) 579 N(0x02A2, "AC Desktop Show All Applications", 0, 0) 580 /* 0x02A3-0x02AF Reserved */ 581 N(0x02B0, "AC Idle Keep Alive", 0, 0) 582 /* 0x02B1-0x02BF Reserved */ 583 N(0x02C0, "Extended Keyboard Attributes Collection", 0, 0) 584 N(0x02C1, "Keyboard Form Factor", 0, 0) 585 N(0x02C2, "Keyboard Key Type", 0, 0) 586 N(0x02C3, "Keyboard Physical Layout", 0, 0) 587 N(0x02C4, "Vendor-Specific Keyboard Physical Layout", 0, 0) 588 N(0x02C5, "Keyboard IETF Language Tag Index", 0, 0) 589 N(0x02C6, "Implemented Keyboard Input Assist Controls", 0, 0) 590 N(0x02C7, "Keyboard Input Assist Previous", 0, 0) 591 N(0x02C8, "Keyboard Input Assist Next", 0, 0) 592 N(0x02C9, "Keyboard Input Assist Previous Group", 0, 0) 593 N(0x02CA, "Keyboard Input Assist Next Group", 0, 0) 594 N(0x02CB, "Keyboard Input Assist Accept", 0, 0) 595 N(0x02CC, "Keyboard Input Assist Cancel", 0, 0) 596 /* 0x02CD-0x02CF Reserved */ 597 N(0x02D0, "Privacy Screen Toggle", 0, 0) 598 N(0x02D1, "Privacy Screen Level Decrement", 0, 0) 599 N(0x02D2, "Privacy Screen Level Increment", 0, 0) 600 N(0x02D3, "Privacy Screen Level Minimum", 0, 0) 601 N(0x02D4, "Privacy Screen Level Maximum", 0, 0) 602 /* 0x02D5-0x04FF Reserved */ 603 N(0x0500, "Contact Edited", 0, 0) 604 N(0x0501, "Contact Added", 0, 0) 605 N(0x0502, "Contact Record Active", 0, 0) 606 N(0x0503, "Contact Index", 0, 0) 607 N(0x0504, "Contact Nickname", 0, 0) 608 N(0x0505, "Contact First Name", 0, 0) 609 N(0x0506, "Contact Last Name", 0, 0) 610 N(0x0507, "Contact Full Name", 0, 0) 611 N(0x0508, "Contact Phone Number Personal", 0, 0) 612 N(0x0509, "Contact Phone Number Business", 0, 0) 613 N(0x050A, "Contact Phone Number Mobile", 0, 0) 614 N(0x050B, "Contact Phone Number Pager", 0, 0) 615 N(0x050C, "Contact Phone Number Fax", 0, 0) 616 N(0x050D, "Contact Phone Number Other", 0, 0) 617 N(0x050E, "Contact Email Personal", 0, 0) 618 N(0x050F, "Contact Email Business", 0, 0) 619 N(0x0510, "Contact Email Other", 0, 0) 620 N(0x0511, "Contact Email Main", 0, 0) 621 N(0x0512, "Contact Speed Dial Number", 0, 0) 622 N(0x0513, "Contact Status Flag", 0, 0) 623 N(0x0514, "Contact Misc.", 0, 0) 624 /* 0x0515-0xFFFF Reserved */ 625 #undef Y 626 #undef N 627 }; 628 629 int 630 ucc_match(struct device *parent, void *match, void *aux) 631 { 632 struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux; 633 void *desc; 634 int size; 635 636 if (UHIDEV_CLAIM_MULTIPLE_REPORTID(uha)) 637 return UMATCH_NONE; 638 639 uhidev_get_report_desc(uha->parent, &desc, &size); 640 if (hid_report_size(desc, size, hid_input, uha->reportid) == 0) 641 return UMATCH_NONE; 642 if (!ucc_hid_match(desc, size, uha->reportid)) 643 return UMATCH_NONE; 644 645 return UMATCH_IFACECLASS; 646 } 647 648 void 649 ucc_attach(struct device *parent, struct device *self, void *aux) 650 { 651 struct ucc_softc *sc = (struct ucc_softc *)self; 652 struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux; 653 void *desc; 654 int error, repid, size; 655 656 sc->sc_mode = WSKBD_TRANSLATED; 657 sc->sc_last_translate = -1; 658 659 sc->sc_hdev.sc_intr = ucc_intr; 660 sc->sc_hdev.sc_parent = uha->parent; 661 sc->sc_hdev.sc_udev = uha->uaa->device; 662 sc->sc_hdev.sc_report_id = uha->reportid; 663 664 uhidev_get_report_desc(uha->parent, &desc, &size); 665 repid = uha->reportid; 666 sc->sc_hdev.sc_isize = hid_report_size(desc, size, hid_input, repid); 667 sc->sc_hdev.sc_osize = hid_report_size(desc, size, hid_output, repid); 668 sc->sc_hdev.sc_fsize = hid_report_size(desc, size, hid_feature, repid); 669 670 error = ucc_hid_parse(sc, desc, size); 671 if (error) { 672 printf(": hid error %d\n", error); 673 return; 674 } 675 676 printf(": %d usage%s, %d key%s, %s\n", 677 sc->sc_nusages, sc->sc_nusages == 1 ? "" : "s", 678 sc->sc_maplen / 2, sc->sc_maplen / 2 == 1 ? "" : "s", 679 sc->sc_isarray ? "array" : "enum"); 680 681 /* Cannot load an empty map. */ 682 if (sc->sc_maplen > 0) 683 ucc_attach_wskbd(sc); 684 } 685 686 int 687 ucc_detach(struct device *self, int flags) 688 { 689 struct ucc_softc *sc = (struct ucc_softc *)self; 690 int error = 0; 691 692 if (sc->sc_wskbddev != NULL) 693 error = config_detach(sc->sc_wskbddev, flags); 694 uhidev_close(&sc->sc_hdev); 695 free(sc->sc_input.i_buf, M_USBDEV, sc->sc_input.i_bufsiz); 696 free(sc->sc_map, M_USBDEV, sc->sc_mapsiz * sizeof(*sc->sc_map)); 697 free(sc->sc_raw, M_USBDEV, sc->sc_rawsiz * sizeof(*sc->sc_raw)); 698 return error; 699 } 700 701 void 702 ucc_intr(struct uhidev *addr, void *data, u_int len) 703 { 704 struct ucc_softc *sc = (struct ucc_softc *)addr; 705 const struct ucc_keysym *us; 706 uint8_t *buf = sc->sc_input.i_buf; 707 int raw = sc->sc_mode == WSKBD_RAW; 708 int error; 709 u_int bit = 0; 710 711 ucc_dump(__func__, data, len); 712 713 if (len > sc->sc_input.i_bufsiz) { 714 DPRINTF("%s: too much data: len %d, bufsiz %d\n", __func__, 715 len, sc->sc_input.i_bufsiz); 716 return; 717 } 718 719 error = ucc_intr_slice(sc, data, buf, &len); 720 if (error) { 721 DPRINTF("%s: slice failure: error %d\n", __func__, error); 722 return; 723 } 724 725 /* Dump the buffer again after slicing. */ 726 ucc_dump(__func__, buf, len); 727 728 if (ucc_setbits(sc, buf, len, &bit)) { 729 /* All zeroes, assume key up event. */ 730 if (raw) { 731 if (sc->sc_last_raw != 0) { 732 ucc_rawinput(sc, sc->sc_last_raw, 1); 733 sc->sc_last_raw = 0; 734 } 735 } else { 736 if (sc->sc_last_translate != -1) { 737 ucc_input(sc, sc->sc_last_translate, 1); 738 sc->sc_last_translate = -1; 739 } 740 } 741 return; 742 } else if (sc->sc_isarray) { 743 int32_t usage; 744 745 if (ucc_bits_to_int(buf, len, &usage) || 746 ucc_usage_to_sym(usage, &us)) 747 goto unknown; 748 bit = us->us_usage; 749 } else if (raw) { 750 if (ucc_bit_to_sym(sc, bit, &us)) 751 goto unknown; 752 } 753 754 if (raw) { 755 ucc_rawinput(sc, us->us_raw, 0); 756 sc->sc_last_raw = us->us_raw; 757 /* 758 * Feed both raw and translating input for keys that have both 759 * defined. This is only the case for volume related keys. 760 */ 761 if (us->us_key == 0) 762 return; 763 } 764 765 ucc_input(sc, bit, 0); 766 if (!raw) 767 sc->sc_last_translate = bit; 768 return; 769 770 unknown: 771 DPRINTF("%s: unknown key: bit %d\n", __func__, bit); 772 } 773 774 void 775 ucc_attach_wskbd(struct ucc_softc *sc) 776 { 777 static const struct wskbd_accessops accessops = { 778 .enable = ucc_enable, 779 .set_leds = ucc_set_leds, 780 .ioctl = ucc_ioctl, 781 }; 782 struct wskbddev_attach_args a = { 783 .console = 0, 784 .keymap = &sc->sc_keymap, 785 .accessops = &accessops, 786 .accesscookie = sc, 787 }; 788 789 sc->sc_keydesc[0].name = KB_US; 790 sc->sc_keydesc[0].base = 0; 791 sc->sc_keydesc[0].map_size = sc->sc_maplen; 792 sc->sc_keydesc[0].map = sc->sc_map; 793 sc->sc_keymap.keydesc = sc->sc_keydesc; 794 sc->sc_keymap.layout = KB_US | KB_NOENCODING; 795 sc->sc_wskbddev = config_found(&sc->sc_hdev.sc_dev, &a, wskbddevprint); 796 } 797 798 int 799 ucc_enable(void *v, int on) 800 { 801 struct ucc_softc *sc = (struct ucc_softc *)v; 802 int error = 0; 803 804 if (on) 805 error = uhidev_open(&sc->sc_hdev); 806 else 807 uhidev_close(&sc->sc_hdev); 808 return error; 809 } 810 811 void 812 ucc_set_leds(void *v, int leds) 813 { 814 } 815 816 int 817 ucc_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 818 { 819 switch (cmd) { 820 /* wsconsctl(8) stub */ 821 case WSKBDIO_GTYPE: 822 *(int *)data = WSKBD_TYPE_USB; 823 return 0; 824 825 /* wsconsctl(8) stub */ 826 case WSKBDIO_GETLEDS: 827 *(int *)data = 0; 828 return 0; 829 830 #ifdef WSDISPLAY_COMPAT_RAWKBD 831 case WSKBDIO_SETMODE: { 832 struct ucc_softc *sc = (struct ucc_softc *)v; 833 834 sc->sc_mode = *(int *)data; 835 return 0; 836 } 837 #endif 838 } 839 840 return -1; 841 } 842 843 /* 844 * Returns non-zero if the given report ID has at least one Consumer Control 845 * usage. 846 */ 847 int 848 ucc_hid_match(void *desc, int descsiz, uint8_t repid) 849 { 850 struct hid_item hi; 851 struct hid_data *hd; 852 int32_t maxusage = 0; 853 854 hd = hid_start_parse(desc, descsiz, hid_input); 855 while (hid_get_item(hd, &hi)) { 856 if (hi.report_ID == repid && 857 hi.kind == hid_input && 858 HID_GET_USAGE_PAGE(hi.usage) == HUP_CONSUMER) { 859 if (HID_GET_USAGE(hi.usage_maximum) > maxusage) 860 maxusage = HID_GET_USAGE(hi.usage_maximum); 861 else if (HID_GET_USAGE(hi.usage) > maxusage) 862 maxusage = HID_GET_USAGE(hi.usage); 863 } 864 } 865 hid_end_parse(hd); 866 return maxusage > 0; 867 } 868 869 /* 870 * Parse the HID report and construct a mapping between the bits in the input 871 * report and the corresponding pressed key. 872 */ 873 int 874 ucc_hid_parse(struct ucc_softc *sc, void *desc, int descsiz) 875 { 876 enum { OFFSET, LENGTH } istate = OFFSET; 877 struct hid_item hi; 878 struct hid_data *hd; 879 u_int bit = 0; 880 int error = 0; 881 int nsyms = nitems(ucc_keysyms); 882 int repid = sc->sc_hdev.sc_report_id; 883 int isize; 884 885 /* 886 * The size of the input report is expressed in bytes where each bit in 887 * turn represents a pressed key. It's likely that the number of keys is 888 * less than this generous estimate. 889 */ 890 isize = sc->sc_hdev.sc_isize * 8; 891 if (isize == 0) 892 return ENXIO; 893 894 /* Allocate buffer used to slice interrupt data. */ 895 sc->sc_input.i_bufsiz = sc->sc_hdev.sc_isize; 896 sc->sc_input.i_buf = malloc(sc->sc_input.i_bufsiz, M_USBDEV, M_WAITOK); 897 898 /* 899 * Create mapping between each input bit and the corresponding usage, 900 * used in translating mode. Two entries are needed per bit in order 901 * construct a mapping. Note that at most all known usages as given by 902 * ucc_keysyms can be inserted into this map. 903 */ 904 sc->sc_mapsiz = nsyms * 2; 905 sc->sc_map = mallocarray(nsyms, 2 * sizeof(*sc->sc_map), M_USBDEV, 906 M_WAITOK | M_ZERO); 907 908 /* 909 * Create mapping between each input bit and the corresponding usage, 910 * used in raw mode. 911 */ 912 sc->sc_rawsiz = isize; 913 sc->sc_raw = mallocarray(isize, sizeof(*sc->sc_raw), M_USBDEV, 914 M_WAITOK | M_ZERO); 915 916 hd = hid_start_parse(desc, descsiz, hid_input); 917 while (hid_get_item(hd, &hi)) { 918 uint32_t off; 919 int32_t usage; 920 921 if (hi.report_ID != repid || hi.kind != hid_input) 922 continue; 923 924 if (HID_GET_USAGE_PAGE(hi.usage) != HUP_CONSUMER) { 925 uint32_t len = hi.loc.size * hi.loc.count; 926 927 switch (istate) { 928 case OFFSET: 929 sc->sc_input.i_off = hi.loc.pos + len; 930 break; 931 case LENGTH: 932 /* Constant padding. */ 933 if (hi.flags & HIO_CONST) 934 sc->sc_input.i_len += len; 935 break; 936 } 937 continue; 938 } 939 940 /* Signal that the input offset is reached. */ 941 istate = LENGTH; 942 off = sc->sc_input.i_len; 943 sc->sc_input.i_len += hi.loc.size * hi.loc.count; 944 945 /* 946 * The usages could be expressed as an array instead of 947 * enumerating all supported ones. 948 */ 949 if (ucc_hid_is_array(&hi)) { 950 error = ucc_hid_parse_array(sc, &hi); 951 break; 952 } 953 954 usage = HID_GET_USAGE(hi.usage); 955 if (usage == HUC_VOLUME) 956 error = ucc_add_key_volume(sc, &hi, off, bit); 957 else 958 error = ucc_add_key(sc, usage, bit); 959 if (error) 960 break; 961 sc->sc_nusages++; 962 bit += hi.loc.size * hi.loc.count; 963 } 964 hid_end_parse(hd); 965 966 DPRINTF("%s: input: off %d, len %d\n", __func__, 967 sc->sc_input.i_off, sc->sc_input.i_len); 968 969 return error; 970 } 971 972 int 973 ucc_hid_parse_array(struct ucc_softc *sc, const struct hid_item *hi) 974 { 975 int32_t max, min, usage; 976 977 min = HID_GET_USAGE(hi->usage_minimum); 978 max = HID_GET_USAGE(hi->usage_maximum); 979 980 sc->sc_nusages = (max - min) + 1; 981 sc->sc_isarray = 1; 982 983 for (usage = min; usage <= max; usage++) { 984 int error; 985 986 error = ucc_add_key(sc, usage, 0); 987 if (error) 988 return error; 989 } 990 991 return 0; 992 } 993 994 int 995 ucc_hid_is_array(const struct hid_item *hi) 996 { 997 int32_t max, min; 998 999 min = HID_GET_USAGE(hi->usage_minimum); 1000 max = HID_GET_USAGE(hi->usage_maximum); 1001 return min >= 0 && max > 0 && min < max; 1002 } 1003 1004 int 1005 ucc_add_key(struct ucc_softc *sc, int32_t usage, u_int bit) 1006 { 1007 const struct ucc_keysym *us; 1008 1009 if (ucc_usage_to_sym(usage, &us)) 1010 return 0; 1011 1012 if (sc->sc_maplen + 2 > sc->sc_mapsiz) 1013 return ENOMEM; 1014 sc->sc_map[sc->sc_maplen++] = KS_KEYCODE(sc->sc_isarray ? usage : bit); 1015 sc->sc_map[sc->sc_maplen++] = us->us_key; 1016 1017 if (!sc->sc_isarray) { 1018 if (bit >= sc->sc_rawsiz) 1019 return ENOMEM; 1020 sc->sc_raw[bit] = us; 1021 } 1022 1023 DPRINTF("%s: bit %d, usage \"%s\"\n", __func__, 1024 bit, us->us_name); 1025 return 0; 1026 } 1027 1028 /* 1029 * Add key mappings for the volume usage which differs compared to the volume 1030 * increment/decrement usages in which each volume change direction is 1031 * represented using a distinct usage. The volume usage instead uses bits of the 1032 * interrupt buffer to represent the wanted volume. The same bits should be 1033 * within the bounds given by the logical min/max associated with the HID item. 1034 */ 1035 int 1036 ucc_add_key_volume(struct ucc_softc *sc, const struct hid_item *hi, 1037 uint32_t off, u_int bit) 1038 { 1039 uint32_t len; 1040 int error; 1041 1042 /* 1043 * Since the volume usage is internally represented using two key 1044 * mappings, make sure enough bits are available to avoid any ambiguity. 1045 */ 1046 len = hi->loc.size * hi->loc.count; 1047 if (len <= 1) 1048 return 1; 1049 1050 sc->sc_volume.v_inc = bit; 1051 sc->sc_volume.v_dec = bit + 1; 1052 sc->sc_volume.v_off = off; 1053 sc->sc_volume.v_len = len; 1054 1055 DPRINTF("%s: inc %d, dec %d, off %d, len %d, min %d, max %d\n", 1056 __func__, sc->sc_volume.v_inc, sc->sc_volume.v_dec, 1057 sc->sc_volume.v_off, sc->sc_volume.v_len, 1058 hi->logical_minimum, hi->logical_maximum); 1059 1060 error = ucc_add_key(sc, HUC_VOL_INC, sc->sc_volume.v_inc); 1061 if (error) 1062 return error; 1063 error = ucc_add_key(sc, HUC_VOL_DEC, sc->sc_volume.v_dec); 1064 if (error) 1065 return error; 1066 return 0; 1067 } 1068 1069 int 1070 ucc_bit_to_sym(struct ucc_softc *sc, u_int bit, const struct ucc_keysym **us) 1071 { 1072 if (bit >= sc->sc_rawsiz || sc->sc_raw[bit] == NULL) 1073 return 1; 1074 *us = sc->sc_raw[bit]; 1075 return 0; 1076 } 1077 1078 int 1079 ucc_usage_to_sym(int32_t usage, const struct ucc_keysym **us) 1080 { 1081 int len = nitems(ucc_keysyms); 1082 int i; 1083 1084 for (i = 0; i < len; i++) { 1085 if (ucc_keysyms[i].us_usage == usage) { 1086 *us = &ucc_keysyms[i]; 1087 return 0; 1088 } 1089 } 1090 return 1; 1091 } 1092 1093 int 1094 ucc_bits_to_int(uint8_t *buf, u_int buflen, int32_t *usage) 1095 { 1096 int32_t x = 0; 1097 int i; 1098 1099 if (buflen == 0 || buflen > sizeof(*usage)) 1100 return 1; 1101 1102 for (i = buflen - 1; i >= 0; i--) { 1103 x |= buf[i]; 1104 if (i > 0) 1105 x <<= 8; 1106 } 1107 *usage = x; 1108 return 0; 1109 } 1110 1111 int 1112 ucc_bits_to_volume(struct ucc_softc *sc, uint8_t *buf, int buflen, u_int *bit) 1113 { 1114 uint32_t vlen = sc->sc_volume.v_len; 1115 uint32_t voff = sc->sc_volume.v_off; 1116 int32_t vol; 1117 int sign; 1118 1119 if (vlen == 0) 1120 return 1; 1121 if (ucc_bits_to_int(buf, buflen, &vol)) 1122 return 1; 1123 vol = (vol >> voff) & ((1 << vlen) - 1); 1124 if (vol == 0) 1125 return 1; 1126 1127 /* 1128 * Interpret the volume as a relative change by only looking at the sign 1129 * in order to determine the change direction. 1130 */ 1131 sign = vol & (1 << (vlen - 1)) ? -1 : 1; 1132 if (sign < 0) 1133 vol = (1 << vlen) - vol; 1134 vol *= sign; 1135 if (vol > 0) 1136 *bit = sc->sc_volume.v_inc; 1137 else 1138 *bit = sc->sc_volume.v_dec; 1139 return 0; 1140 } 1141 1142 int 1143 ucc_intr_slice(struct ucc_softc *sc, uint8_t *src, uint8_t *dst, int *len) 1144 { 1145 int ilen = sc->sc_input.i_len; 1146 int ioff = sc->sc_input.i_off; 1147 int maxlen = *len; 1148 int di, si; 1149 1150 if (maxlen == 0) 1151 return 1; 1152 1153 memset(dst, 0, maxlen); 1154 si = ioff; 1155 di = 0; 1156 for (; ilen > 0; ilen--) { 1157 int db, sb; 1158 1159 sb = si / 8; 1160 db = di / 8; 1161 if (sb >= maxlen || db >= maxlen) 1162 return 1; 1163 1164 if (src[sb] & (1 << (si % 8))) 1165 dst[db] |= 1 << (di % 8); 1166 si++; 1167 di++; 1168 } 1169 1170 *len = (sc->sc_input.i_len + 7) / 8; 1171 return 0; 1172 } 1173 1174 void 1175 ucc_input(struct ucc_softc *sc, u_int bit, int release) 1176 { 1177 int s; 1178 1179 s = spltty(); 1180 wskbd_input(sc->sc_wskbddev, 1181 release ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN, bit); 1182 splx(s); 1183 } 1184 1185 void 1186 ucc_rawinput(struct ucc_softc *sc, u_char c, int release) 1187 { 1188 #ifdef WSDISPLAY_COMPAT_RAWKBD 1189 u_char buf[2]; 1190 int len = 0; 1191 int s; 1192 1193 if (c & 0x80) 1194 buf[len++] = 0xe0; 1195 buf[len++] = c & 0x7f; 1196 if (release) 1197 buf[len - 1] |= 0x80; 1198 1199 s = spltty(); 1200 wskbd_rawinput(sc->sc_wskbddev, buf, len); 1201 splx(s); 1202 #endif 1203 } 1204 1205 int 1206 ucc_setbits(struct ucc_softc *sc, uint8_t *data, int len, u_int *bit) 1207 { 1208 int i, j; 1209 1210 if (ucc_bits_to_volume(sc, data, len, bit) == 0) 1211 return 0; 1212 1213 for (i = 0; i < len; i++) { 1214 if (data[i] == 0) 1215 continue; 1216 1217 for (j = 0; j < 8; j++) { 1218 if (data[i] & (1 << j)) { 1219 *bit = (i * 8) + j; 1220 return 0; 1221 } 1222 } 1223 } 1224 1225 return 1; 1226 } 1227 1228 #ifdef UCC_DEBUG 1229 1230 void 1231 ucc_dump(const char *prefix, uint8_t *data, u_int len) 1232 { 1233 u_int i; 1234 1235 if (ucc_debug == 0) 1236 return; 1237 1238 printf("%s:", prefix); 1239 for (i = 0; i < len; i++) 1240 printf(" %02x", data[i]); 1241 printf("\n"); 1242 } 1243 1244 #endif 1245