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