xref: /openbsd-src/sys/dev/hid/hidcc.c (revision 53a69a909e7144bba9b0c7135a0bdf01e45b708f)
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