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