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