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