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