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