1 /* $OpenBSD: ucc.c,v 1.27 2021/09/20 17:32:39 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 uhidev_get_report_desc(uha->parent, &desc, &size); 637 if (hid_report_size(desc, size, hid_input, uha->reportid) == 0) 638 return UMATCH_NONE; 639 if (!ucc_hid_match(desc, size, uha->reportid)) 640 return UMATCH_NONE; 641 642 return UMATCH_IFACECLASS; 643 } 644 645 void 646 ucc_attach(struct device *parent, struct device *self, void *aux) 647 { 648 struct ucc_softc *sc = (struct ucc_softc *)self; 649 struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux; 650 void *desc; 651 int error, repid, size; 652 653 sc->sc_mode = WSKBD_TRANSLATED; 654 sc->sc_last_translate = -1; 655 656 sc->sc_hdev.sc_intr = ucc_intr; 657 sc->sc_hdev.sc_parent = uha->parent; 658 sc->sc_hdev.sc_udev = uha->uaa->device; 659 sc->sc_hdev.sc_report_id = uha->reportid; 660 661 uhidev_get_report_desc(uha->parent, &desc, &size); 662 repid = uha->reportid; 663 sc->sc_hdev.sc_isize = hid_report_size(desc, size, hid_input, repid); 664 sc->sc_hdev.sc_osize = hid_report_size(desc, size, hid_output, repid); 665 sc->sc_hdev.sc_fsize = hid_report_size(desc, size, hid_feature, repid); 666 667 error = ucc_hid_parse(sc, desc, size); 668 if (error) { 669 printf(": hid error %d\n", error); 670 return; 671 } 672 673 printf(": %d usage%s, %d key%s, %s\n", 674 sc->sc_nusages, sc->sc_nusages == 1 ? "" : "s", 675 sc->sc_maplen / 2, sc->sc_maplen / 2 == 1 ? "" : "s", 676 sc->sc_isarray ? "array" : "enum"); 677 678 /* Cannot load an empty map. */ 679 if (sc->sc_maplen > 0) 680 ucc_attach_wskbd(sc); 681 } 682 683 int 684 ucc_detach(struct device *self, int flags) 685 { 686 struct ucc_softc *sc = (struct ucc_softc *)self; 687 int error = 0; 688 689 if (sc->sc_wskbddev != NULL) 690 error = config_detach(sc->sc_wskbddev, flags); 691 uhidev_close(&sc->sc_hdev); 692 free(sc->sc_input.i_buf, M_USBDEV, sc->sc_input.i_bufsiz); 693 free(sc->sc_map, M_USBDEV, sc->sc_mapsiz * sizeof(*sc->sc_map)); 694 free(sc->sc_raw, M_USBDEV, sc->sc_rawsiz * sizeof(*sc->sc_raw)); 695 return error; 696 } 697 698 void 699 ucc_intr(struct uhidev *addr, void *data, u_int len) 700 { 701 struct ucc_softc *sc = (struct ucc_softc *)addr; 702 const struct ucc_keysym *us; 703 uint8_t *buf = sc->sc_input.i_buf; 704 int raw = sc->sc_mode == WSKBD_RAW; 705 int error; 706 u_int bit = 0; 707 708 ucc_dump(__func__, data, len); 709 710 if (len > sc->sc_input.i_bufsiz) { 711 DPRINTF("%s: too much data: len %d, bufsiz %d\n", __func__, 712 len, sc->sc_input.i_bufsiz); 713 return; 714 } 715 716 error = ucc_intr_slice(sc, data, buf, &len); 717 if (error) { 718 DPRINTF("%s: slice failure: error %d\n", __func__, error); 719 return; 720 } 721 722 /* Dump the buffer again after slicing. */ 723 ucc_dump(__func__, buf, len); 724 725 if (ucc_setbits(sc, buf, len, &bit)) { 726 /* All zeroes, assume key up event. */ 727 if (raw) { 728 if (sc->sc_last_raw != 0) { 729 ucc_rawinput(sc, sc->sc_last_raw, 1); 730 sc->sc_last_raw = 0; 731 } 732 } else { 733 if (sc->sc_last_translate != -1) { 734 ucc_input(sc, sc->sc_last_translate, 1); 735 sc->sc_last_translate = -1; 736 } 737 } 738 return; 739 } else if (sc->sc_isarray) { 740 int32_t usage; 741 742 if (ucc_bits_to_int(buf, len, &usage) || 743 ucc_usage_to_sym(usage, &us)) 744 goto unknown; 745 bit = us->us_usage; 746 } else if (raw) { 747 if (ucc_bit_to_sym(sc, bit, &us)) 748 goto unknown; 749 } 750 751 if (raw) { 752 ucc_rawinput(sc, us->us_raw, 0); 753 sc->sc_last_raw = us->us_raw; 754 /* 755 * Feed both raw and translating input for keys that have both 756 * defined. This is only the case for volume related keys. 757 */ 758 if (us->us_key == 0) 759 return; 760 } 761 762 ucc_input(sc, bit, 0); 763 if (!raw) 764 sc->sc_last_translate = bit; 765 return; 766 767 unknown: 768 DPRINTF("%s: unknown key: bit %d\n", __func__, bit); 769 } 770 771 void 772 ucc_attach_wskbd(struct ucc_softc *sc) 773 { 774 static const struct wskbd_accessops accessops = { 775 .enable = ucc_enable, 776 .set_leds = ucc_set_leds, 777 .ioctl = ucc_ioctl, 778 }; 779 struct wskbddev_attach_args a = { 780 .console = 0, 781 .keymap = &sc->sc_keymap, 782 .accessops = &accessops, 783 .accesscookie = sc, 784 }; 785 786 sc->sc_keydesc[0].name = KB_US; 787 sc->sc_keydesc[0].base = 0; 788 sc->sc_keydesc[0].map_size = sc->sc_maplen; 789 sc->sc_keydesc[0].map = sc->sc_map; 790 sc->sc_keymap.keydesc = sc->sc_keydesc; 791 sc->sc_keymap.layout = KB_US | KB_NOENCODING; 792 sc->sc_wskbddev = config_found(&sc->sc_hdev.sc_dev, &a, wskbddevprint); 793 } 794 795 int 796 ucc_enable(void *v, int on) 797 { 798 struct ucc_softc *sc = (struct ucc_softc *)v; 799 int error = 0; 800 801 if (on) 802 error = uhidev_open(&sc->sc_hdev); 803 else 804 uhidev_close(&sc->sc_hdev); 805 return error; 806 } 807 808 void 809 ucc_set_leds(void *v, int leds) 810 { 811 } 812 813 int 814 ucc_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 815 { 816 switch (cmd) { 817 /* wsconsctl(8) stub */ 818 case WSKBDIO_GTYPE: 819 *(int *)data = WSKBD_TYPE_USB; 820 return 0; 821 822 /* wsconsctl(8) stub */ 823 case WSKBDIO_GETLEDS: 824 *(int *)data = 0; 825 return 0; 826 827 #ifdef WSDISPLAY_COMPAT_RAWKBD 828 case WSKBDIO_SETMODE: { 829 struct ucc_softc *sc = (struct ucc_softc *)v; 830 831 sc->sc_mode = *(int *)data; 832 return 0; 833 } 834 #endif 835 } 836 837 return -1; 838 } 839 840 /* 841 * Returns non-zero if the given report ID has at least one Consumer Control 842 * usage. 843 */ 844 int 845 ucc_hid_match(void *desc, int descsiz, uint8_t repid) 846 { 847 struct hid_item hi; 848 struct hid_data *hd; 849 int32_t maxusage = 0; 850 851 hd = hid_start_parse(desc, descsiz, hid_input); 852 while (hid_get_item(hd, &hi)) { 853 if (hi.report_ID == repid && 854 hi.kind == hid_input && 855 HID_GET_USAGE_PAGE(hi.usage) == HUP_CONSUMER) { 856 if (HID_GET_USAGE(hi.usage_maximum) > maxusage) 857 maxusage = HID_GET_USAGE(hi.usage_maximum); 858 else if (HID_GET_USAGE(hi.usage) > maxusage) 859 maxusage = HID_GET_USAGE(hi.usage); 860 } 861 } 862 hid_end_parse(hd); 863 return maxusage > 0; 864 } 865 866 /* 867 * Parse the HID report and construct a mapping between the bits in the input 868 * report and the corresponding pressed key. 869 */ 870 int 871 ucc_hid_parse(struct ucc_softc *sc, void *desc, int descsiz) 872 { 873 enum { OFFSET, LENGTH } istate = OFFSET; 874 struct hid_item hi; 875 struct hid_data *hd; 876 u_int bit = 0; 877 int error = 0; 878 int nsyms = nitems(ucc_keysyms); 879 int repid = sc->sc_hdev.sc_report_id; 880 int isize; 881 882 /* 883 * The size of the input report is expressed in bytes where each bit in 884 * turn represents a pressed key. It's likely that the number of keys is 885 * less than this generous estimate. 886 */ 887 isize = sc->sc_hdev.sc_isize * 8; 888 if (isize == 0) 889 return ENXIO; 890 891 /* Allocate buffer used to slice interrupt data. */ 892 sc->sc_input.i_bufsiz = sc->sc_hdev.sc_isize; 893 sc->sc_input.i_buf = malloc(sc->sc_input.i_bufsiz, M_USBDEV, M_WAITOK); 894 895 /* 896 * Create mapping between each input bit and the corresponding usage, 897 * used in translating mode. Two entries are needed per bit in order 898 * construct a mapping. Note that at most all known usages as given by 899 * ucc_keysyms can be inserted into this map. 900 */ 901 sc->sc_mapsiz = nsyms * 2; 902 sc->sc_map = mallocarray(nsyms, 2 * sizeof(*sc->sc_map), M_USBDEV, 903 M_WAITOK | M_ZERO); 904 905 /* 906 * Create mapping between each input bit and the corresponding usage, 907 * used in raw mode. 908 */ 909 sc->sc_rawsiz = isize; 910 sc->sc_raw = mallocarray(isize, sizeof(*sc->sc_raw), M_USBDEV, 911 M_WAITOK | M_ZERO); 912 913 hd = hid_start_parse(desc, descsiz, hid_input); 914 while (hid_get_item(hd, &hi)) { 915 uint32_t off; 916 int32_t usage; 917 918 if (hi.report_ID != repid || hi.kind != hid_input) 919 continue; 920 921 if (HID_GET_USAGE_PAGE(hi.usage) != HUP_CONSUMER) { 922 uint32_t len = hi.loc.size * hi.loc.count; 923 924 switch (istate) { 925 case OFFSET: 926 sc->sc_input.i_off = hi.loc.pos + len; 927 break; 928 case LENGTH: 929 /* Constant padding. */ 930 if (hi.flags & HIO_CONST) 931 sc->sc_input.i_len += len; 932 break; 933 } 934 continue; 935 } 936 937 /* Signal that the input offset is reached. */ 938 istate = LENGTH; 939 off = sc->sc_input.i_len; 940 sc->sc_input.i_len += hi.loc.size * hi.loc.count; 941 942 /* 943 * The usages could be expressed as an array instead of 944 * enumerating all supported ones. 945 */ 946 if (ucc_hid_is_array(&hi)) { 947 error = ucc_hid_parse_array(sc, &hi); 948 break; 949 } 950 951 usage = HID_GET_USAGE(hi.usage); 952 if (usage == HUC_VOLUME) 953 error = ucc_add_key_volume(sc, &hi, off, bit); 954 else 955 error = ucc_add_key(sc, usage, bit); 956 if (error) 957 break; 958 sc->sc_nusages++; 959 bit += hi.loc.size * hi.loc.count; 960 } 961 hid_end_parse(hd); 962 963 DPRINTF("%s: input: off %d, len %d\n", __func__, 964 sc->sc_input.i_off, sc->sc_input.i_len); 965 966 return error; 967 } 968 969 int 970 ucc_hid_parse_array(struct ucc_softc *sc, const struct hid_item *hi) 971 { 972 int32_t max, min, usage; 973 974 min = HID_GET_USAGE(hi->usage_minimum); 975 max = HID_GET_USAGE(hi->usage_maximum); 976 977 sc->sc_nusages = (max - min) + 1; 978 sc->sc_isarray = 1; 979 980 for (usage = min; usage <= max; usage++) { 981 int error; 982 983 error = ucc_add_key(sc, usage, 0); 984 if (error) 985 return error; 986 } 987 988 return 0; 989 } 990 991 int 992 ucc_hid_is_array(const struct hid_item *hi) 993 { 994 int32_t max, min; 995 996 min = HID_GET_USAGE(hi->usage_minimum); 997 max = HID_GET_USAGE(hi->usage_maximum); 998 return min >= 0 && max > 0 && min < max; 999 } 1000 1001 int 1002 ucc_add_key(struct ucc_softc *sc, int32_t usage, u_int bit) 1003 { 1004 const struct ucc_keysym *us; 1005 1006 if (ucc_usage_to_sym(usage, &us)) 1007 return 0; 1008 1009 if (sc->sc_maplen + 2 > sc->sc_mapsiz) 1010 return ENOMEM; 1011 sc->sc_map[sc->sc_maplen++] = KS_KEYCODE(sc->sc_isarray ? usage : bit); 1012 sc->sc_map[sc->sc_maplen++] = us->us_key; 1013 1014 if (!sc->sc_isarray) { 1015 if (bit >= sc->sc_rawsiz) 1016 return ENOMEM; 1017 sc->sc_raw[bit] = us; 1018 } 1019 1020 DPRINTF("%s: bit %d, usage \"%s\"\n", __func__, 1021 bit, us->us_name); 1022 return 0; 1023 } 1024 1025 /* 1026 * Add key mappings for the volume usage which differs compared to the volume 1027 * increment/decrement usages in which each volume change direction is 1028 * represented using a distinct usage. The volume usage instead uses bits of the 1029 * interrupt buffer to represent the wanted volume. The same bits should be 1030 * within the bounds given by the logical min/max associated with the HID item. 1031 */ 1032 int 1033 ucc_add_key_volume(struct ucc_softc *sc, const struct hid_item *hi, 1034 uint32_t off, u_int bit) 1035 { 1036 uint32_t len; 1037 int error; 1038 1039 /* 1040 * Since the volume usage is internally represented using two key 1041 * mappings, make sure enough bits are available to avoid any ambiguity. 1042 */ 1043 len = hi->loc.size * hi->loc.count; 1044 if (len <= 1) 1045 return 1; 1046 1047 sc->sc_volume.v_inc = bit; 1048 sc->sc_volume.v_dec = bit + 1; 1049 sc->sc_volume.v_off = off; 1050 sc->sc_volume.v_len = len; 1051 1052 DPRINTF("%s: inc %d, dec %d, off %d, len %d, min %d, max %d\n", 1053 __func__, sc->sc_volume.v_inc, sc->sc_volume.v_dec, 1054 sc->sc_volume.v_off, sc->sc_volume.v_len, 1055 hi->logical_minimum, hi->logical_maximum); 1056 1057 error = ucc_add_key(sc, HUC_VOL_INC, sc->sc_volume.v_inc); 1058 if (error) 1059 return error; 1060 error = ucc_add_key(sc, HUC_VOL_DEC, sc->sc_volume.v_dec); 1061 if (error) 1062 return error; 1063 return 0; 1064 } 1065 1066 int 1067 ucc_bit_to_sym(struct ucc_softc *sc, u_int bit, const struct ucc_keysym **us) 1068 { 1069 if (bit >= sc->sc_rawsiz || sc->sc_raw[bit] == NULL) 1070 return 1; 1071 *us = sc->sc_raw[bit]; 1072 return 0; 1073 } 1074 1075 int 1076 ucc_usage_to_sym(int32_t usage, const struct ucc_keysym **us) 1077 { 1078 int len = nitems(ucc_keysyms); 1079 int i; 1080 1081 for (i = 0; i < len; i++) { 1082 if (ucc_keysyms[i].us_usage == usage) { 1083 *us = &ucc_keysyms[i]; 1084 return 0; 1085 } 1086 } 1087 return 1; 1088 } 1089 1090 int 1091 ucc_bits_to_int(uint8_t *buf, u_int buflen, int32_t *usage) 1092 { 1093 int32_t x = 0; 1094 int i; 1095 1096 if (buflen == 0 || buflen > sizeof(*usage)) 1097 return 1; 1098 1099 for (i = buflen - 1; i >= 0; i--) { 1100 x |= buf[i]; 1101 if (i > 0) 1102 x <<= 8; 1103 } 1104 *usage = x; 1105 return 0; 1106 } 1107 1108 int 1109 ucc_bits_to_volume(struct ucc_softc *sc, uint8_t *buf, int buflen, u_int *bit) 1110 { 1111 uint32_t vlen = sc->sc_volume.v_len; 1112 uint32_t voff = sc->sc_volume.v_off; 1113 int32_t vol; 1114 int sign; 1115 1116 if (vlen == 0) 1117 return 1; 1118 if (ucc_bits_to_int(buf, buflen, &vol)) 1119 return 1; 1120 vol = (vol >> voff) & ((1 << vlen) - 1); 1121 if (vol == 0) 1122 return 1; 1123 1124 /* 1125 * Interpret the volume as a relative change by only looking at the sign 1126 * in order to determine the change direction. 1127 */ 1128 sign = vol & (1 << (vlen - 1)) ? -1 : 1; 1129 if (sign < 0) 1130 vol = (1 << vlen) - vol; 1131 vol *= sign; 1132 if (vol > 0) 1133 *bit = sc->sc_volume.v_inc; 1134 else 1135 *bit = sc->sc_volume.v_dec; 1136 return 0; 1137 } 1138 1139 int 1140 ucc_intr_slice(struct ucc_softc *sc, uint8_t *src, uint8_t *dst, int *len) 1141 { 1142 int ilen = sc->sc_input.i_len; 1143 int ioff = sc->sc_input.i_off; 1144 int maxlen = *len; 1145 int di, si; 1146 1147 if (maxlen == 0) 1148 return 1; 1149 1150 memset(dst, 0, maxlen); 1151 si = ioff; 1152 di = 0; 1153 for (; ilen > 0; ilen--) { 1154 int db, sb; 1155 1156 sb = si / 8; 1157 db = di / 8; 1158 if (sb >= maxlen || db >= maxlen) 1159 return 1; 1160 1161 if (src[sb] & (1 << (si % 8))) 1162 dst[db] |= 1 << (di % 8); 1163 si++; 1164 di++; 1165 } 1166 1167 *len = (sc->sc_input.i_len + 7) / 8; 1168 return 0; 1169 } 1170 1171 void 1172 ucc_input(struct ucc_softc *sc, u_int bit, int release) 1173 { 1174 int s; 1175 1176 s = spltty(); 1177 wskbd_input(sc->sc_wskbddev, 1178 release ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN, bit); 1179 splx(s); 1180 } 1181 1182 void 1183 ucc_rawinput(struct ucc_softc *sc, u_char c, int release) 1184 { 1185 #ifdef WSDISPLAY_COMPAT_RAWKBD 1186 u_char buf[2]; 1187 int len = 0; 1188 int s; 1189 1190 if (c & 0x80) 1191 buf[len++] = 0xe0; 1192 buf[len++] = c & 0x7f; 1193 if (release) 1194 buf[len - 1] |= 0x80; 1195 1196 s = spltty(); 1197 wskbd_rawinput(sc->sc_wskbddev, buf, len); 1198 splx(s); 1199 #endif 1200 } 1201 1202 int 1203 ucc_setbits(struct ucc_softc *sc, uint8_t *data, int len, u_int *bit) 1204 { 1205 int i, j; 1206 1207 if (ucc_bits_to_volume(sc, data, len, bit) == 0) 1208 return 0; 1209 1210 for (i = 0; i < len; i++) { 1211 if (data[i] == 0) 1212 continue; 1213 1214 for (j = 0; j < 8; j++) { 1215 if (data[i] & (1 << j)) { 1216 *bit = (i * 8) + j; 1217 return 0; 1218 } 1219 } 1220 } 1221 1222 return 1; 1223 } 1224 1225 #ifdef UCC_DEBUG 1226 1227 void 1228 ucc_dump(const char *prefix, uint8_t *data, u_int len) 1229 { 1230 u_int i; 1231 1232 if (ucc_debug == 0) 1233 return; 1234 1235 printf("%s:", prefix); 1236 for (i = 0; i < len; i++) 1237 printf(" %02x", data[i]); 1238 printf("\n"); 1239 } 1240 1241 #endif 1242