1 /*
2  * Copyright (c) 2018, Joyent, Inc.
3  */
4 
5 /*
6  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
7  * Use is subject to license terms.
8  */
9 
10 /*
11  * Copyright (c) 2007, 2008 Bartosz Fabianowski <freebsd@chillt.de>
12  * All rights reserved.
13  *
14  * Financed by the "Irish Research Council for Science, Engineering and
15  * Technology: funded by the National Development Plan"
16  *
17  * Redistribution and use in source and binary forms, with or without
18  * modification, are permitted provided that the following conditions
19  * are met:
20  * 1. Redistributions of source code must retain the above copyright
21  *    notice, this list of conditions, and the following disclaimer.
22  * 2. Redistributions in binary form must reproduce the above copyright
23  *    notice, this list of conditions and the following disclaimer in the
24  *    documentation and/or other materials provided with the distribution.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
30  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  */
38 
39 /*
40  * Copyright (c) 1998 The NetBSD Foundation, Inc.
41  * All rights reserved.
42  *
43  * This code is derived from software contributed to The NetBSD Foundation
44  * by Lennart Augustsson (lennart@augustsson.net) at
45  * Carlstedt Research & Technology.
46  *
47  * Redistribution and use in source and binary forms, with or without
48  * modification, are permitted provided that the following conditions
49  * are met:
50  * 1. Redistributions of source code must retain the above copyright
51  *    notice, this list of conditions and the following disclaimer.
52  * 2. Redistributions in binary form must reproduce the above copyright
53  *    notice, this list of conditions and the following disclaimer in the
54  *    documentation and/or other materials provided with the distribution.
55  * 3. All advertising materials mentioning features or use of this software
56  *    must display the following acknowledgement:
57  *        This product includes software developed by the NetBSD
58  *        Foundation, Inc. and its contributors.
59  * 4. Neither the name of The NetBSD Foundation nor the names of its
60  *    contributors may be used to endorse or promote products derived
61  *    from this software without specific prior written permission.
62  *
63  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
64  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
65  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
66  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
67  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
68  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
69  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
70  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
71  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
72  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
73  * POSSIBILITY OF SUCH DAMAGE.
74  */
75 
76 #include <sys/stropts.h>
77 #include <sys/strsun.h>
78 #include <sys/termios.h>
79 #include <sys/termio.h>
80 #include <sys/strtty.h>
81 #include <sys/systm.h>
82 
83 #include <sys/usb/usba/usbai_version.h>
84 #include <sys/usb/usba.h>
85 #include <sys/usb/usba/usbai_private.h>
86 #include <sys/usb/clients/hid/hid.h>
87 #include <sys/usb/clients/usbinput/usbwcm/usbwcm.h>
88 
89 /* debugging information */
90 uint_t	usbwcm_errmask = (uint_t)PRINT_MASK_ALL;
91 uint_t	usbwcm_errlevel = USB_LOG_L2;
92 static usb_log_handle_t usbwcm_log_handle;
93 
94 static void
uwacom_event(usbwcm_state_t * usbwcmp,uint_t type,uint_t idx,int val)95 uwacom_event(usbwcm_state_t *usbwcmp, uint_t type, uint_t idx, int val)
96 {
97 	struct uwacom_softc	*sc = &usbwcmp->usbwcm_softc;
98 	mblk_t			*mp;
99 
100 	switch (type) {
101 	case EVT_SYN:
102 		if (sc->sc_sync)
103 			return;
104 		break;
105 
106 	case EVT_BTN:
107 		if (sc->sc_btn[idx] == val)
108 			return;
109 
110 		sc->sc_btn[idx] = val;
111 		break;
112 
113 	case EVT_ABS:
114 		if (sc->sc_abs[idx].fuzz) {
115 			int dist = abs(val - sc->sc_abs[idx].value);
116 
117 			if (dist < sc->sc_abs[idx].fuzz >> 1) {
118 				return;
119 			} else if (dist < sc->sc_abs[idx].fuzz) {
120 				val = (7 * sc->sc_abs[idx].value + val) >> 3;
121 			} else if (dist < sc->sc_abs[idx].fuzz << 1) {
122 				val = (sc->sc_abs[idx].value + val) >> 1;
123 			}
124 		}
125 		if (sc->sc_abs[idx].value == val) {
126 			return;
127 		}
128 
129 		sc->sc_abs[idx].value = val;
130 		break;
131 
132 	case EVT_REL:
133 		if (!val)
134 			return;
135 		break;
136 
137 	case EVT_MSC:
138 		break;
139 
140 	default:
141 		return;
142 	}
143 
144 	if ((mp = allocb(sizeof (struct event_input), BPRI_HI)) != NULL) {
145 		struct event_input *ev = (struct event_input *)mp->b_wptr;
146 
147 		ev->type = (uint16_t)type;
148 		ev->code = (uint16_t)idx;
149 		ev->value = (int32_t)val;
150 		uniqtime32(&ev->time);
151 
152 		mp->b_wptr += sizeof (struct event_input);
153 		putnext(usbwcmp->usbwcm_rq, mp);
154 	} else {
155 		return;
156 	}
157 
158 	sc->sc_sync = (type == EVT_SYN);
159 }
160 
161 static void
uwacom_pos_events_graphire(usbwcm_state_t * usbwcmp,int x,int y)162 uwacom_pos_events_graphire(usbwcm_state_t *usbwcmp, int x, int y)
163 {
164 	uwacom_event(usbwcmp, EVT_ABS, ABS_X, x);
165 	uwacom_event(usbwcmp, EVT_ABS, ABS_Y, y);
166 }
167 
168 static void
uwacom_pen_events_graphire(usbwcm_state_t * usbwcmp,int prs,int stl1,int stl2)169 uwacom_pen_events_graphire(usbwcm_state_t *usbwcmp, int prs, int stl1, int stl2)
170 {
171 	uwacom_event(usbwcmp, EVT_ABS, ABS_PRESSURE, prs);
172 	uwacom_event(usbwcmp, EVT_BTN, BTN_TIP, prs);
173 	uwacom_event(usbwcmp, EVT_BTN, BTN_STYLUS_1, stl1);
174 	uwacom_event(usbwcmp, EVT_BTN, BTN_STYLUS_2, stl2);
175 }
176 
177 static void
uwacom_mouse_events_graphire(usbwcm_state_t * usbwcmp,int left,int middle,int right,int wheel,int distance)178 uwacom_mouse_events_graphire(usbwcm_state_t *usbwcmp, int left, int middle,
179     int right, int wheel, int distance)
180 {
181 	uwacom_event(usbwcmp, EVT_BTN, BTN_LEFT, left);
182 	uwacom_event(usbwcmp, EVT_BTN, BTN_MIDDLE, middle);
183 	uwacom_event(usbwcmp, EVT_BTN, BTN_RIGHT, right);
184 	uwacom_event(usbwcmp, EVT_REL, REL_WHEEL, wheel);
185 	uwacom_event(usbwcmp, EVT_ABS, ABS_DISTANCE, distance);
186 }
187 
188 static void
uwacom_tool_events_graphire(usbwcm_state_t * usbwcmp,int idx,int proximity)189 uwacom_tool_events_graphire(usbwcm_state_t *usbwcmp, int idx, int proximity)
190 {
191 	struct uwacom_softc *sc = &usbwcmp->usbwcm_softc;
192 
193 	uwacom_event(usbwcmp, EVT_BTN, sc->sc_tool[idx], proximity);
194 	uwacom_event(usbwcmp, EVT_ABS, ABS_MISC, sc->sc_tool_id[idx]);
195 	if (sc->sc_serial[idx]) {
196 		uwacom_event(usbwcmp, EVT_MSC, MSC_SERIAL, sc->sc_serial[idx]);
197 	}
198 
199 	uwacom_event(usbwcmp, EVT_SYN, SYN_REPORT, 0);
200 }
201 
202 static void
uwacom_pad_events_graphire4(usbwcm_state_t * usbwcmp,int b0,int b1,int b4,int b5,int rel,int abs)203 uwacom_pad_events_graphire4(usbwcm_state_t *usbwcmp, int b0, int b1, int b4,
204     int b5, int rel, int abs)
205 {
206 	uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_0, b0);
207 	uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_1, b1);
208 	uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_4, b4);
209 	uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_5, b5);
210 	uwacom_event(usbwcmp, EVT_REL, REL_WHEEL, rel);
211 	uwacom_event(usbwcmp, EVT_ABS, ABS_WHEEL, abs);
212 	uwacom_tool_events_graphire(usbwcmp, 1, b0 | b1 | b4 | b5 | rel | abs);
213 }
214 
215 static void
usbwcm_input_graphire(usbwcm_state_t * usbwcmp,mblk_t * mp)216 usbwcm_input_graphire(usbwcm_state_t *usbwcmp, mblk_t *mp)
217 {
218 	struct uwacom_softc *sc = &usbwcmp->usbwcm_softc;
219 	uint8_t *packet = mp->b_rptr;
220 
221 	if (PACKET_BITS(0, 0, 8) != 0x02) {
222 		USB_DPRINTF_L1(PRINT_MASK_ALL, usbwcm_log_handle,
223 		    "unknown report type %02x received\n",
224 		    PACKET_BITS(0, 0, 8));
225 		return;
226 	}
227 
228 	/* Tool in proximity */
229 	if (PACKET_BIT(1, 7)) {
230 		uwacom_pos_events_graphire(usbwcmp,
231 		    (PACKET_BITS(3, 0, 8) << 8) | PACKET_BITS(2, 0, 8),
232 		    (PACKET_BITS(5, 0, 8) << 8) | PACKET_BITS(4, 0, 8));
233 
234 		if (!PACKET_BIT(1, 6)) {
235 			if (!PACKET_BIT(1, 5)) {
236 				sc->sc_tool[0] = BTN_TOOL_PEN;
237 				sc->sc_tool_id[0] = TOOL_ID_PEN;
238 			} else {
239 				sc->sc_tool[0] = BTN_TOOL_ERASER;
240 				sc->sc_tool_id[0] = TOOL_ID_ERASER;
241 			}
242 
243 			uwacom_pen_events_graphire(usbwcmp,
244 			    (PACKET_BIT(7, 0) << 8) | PACKET_BITS(6, 0, 8),
245 			    PACKET_BIT(1, 1), PACKET_BIT(1, 2));
246 		} else {
247 			int wheel, distance;
248 
249 			if (sc->sc_type->protocol == GRAPHIRE) {
250 				wheel = (PACKET_BIT(1, 5) ?
251 				    0 : -(int8_t)PACKET_BITS(6, 0, 8));
252 				distance = PACKET_BITS(7, 0, 6);
253 			} else {
254 				wheel = (PACKET_BIT(7, 2) << 2) -
255 				    PACKET_BITS(7, 0, 2);
256 				distance = PACKET_BITS(6, 0, 6);
257 			}
258 
259 			sc->sc_tool[0] = BTN_TOOL_MOUSE;
260 			sc->sc_tool_id[0] = TOOL_ID_MOUSE;
261 
262 			uwacom_mouse_events_graphire(usbwcmp, PACKET_BIT(1, 0),
263 			    PACKET_BIT(1, 2), PACKET_BIT(1, 1), wheel,
264 			    distance);
265 		}
266 
267 		uwacom_tool_events_graphire(usbwcmp, 0, 1);
268 
269 		/* Tool leaving proximity */
270 	} else if (sc->sc_tool_id[0]) {
271 		uwacom_pos_events_graphire(usbwcmp, 0, 0);
272 
273 		if (sc->sc_tool[0] == BTN_TOOL_MOUSE)
274 			uwacom_mouse_events_graphire(usbwcmp, 0, 0, 0, 0, 0);
275 		else
276 			uwacom_pen_events_graphire(usbwcmp, 0, 0, 0);
277 
278 		sc->sc_tool_id[0] = 0;
279 		uwacom_tool_events_graphire(usbwcmp, 0, 0);
280 	}
281 
282 	/* Finger on pad: Graphire4 */
283 	if ((sc->sc_type->protocol == GRAPHIRE4) && PACKET_BITS(7, 3, 5)) {
284 		sc->sc_tool_id[1] = TOOL_ID_PAD;
285 		uwacom_pad_events_graphire4(usbwcmp, PACKET_BIT(7, 6), 0,
286 		    PACKET_BIT(7, 7), 0,
287 		    PACKET_BITS(7, 3, 2) - (PACKET_BIT(7, 5) << 2), 0);
288 
289 	/* Finger on pad: MyOffice */
290 	} else if ((sc->sc_type->protocol == MYOFFICE) &&
291 	    (PACKET_BITS(7, 3, 4) || PACKET_BITS(8, 0, 8))) {
292 		sc->sc_tool_id[1] = TOOL_ID_PAD;
293 		uwacom_pad_events_graphire4(usbwcmp, PACKET_BIT(7, 3),
294 		    PACKET_BIT(7, 4), PACKET_BIT(7, 5), PACKET_BIT(7, 6), 0,
295 		    PACKET_BITS(8, 0, 7));
296 
297 	/* Finger leaving pad */
298 	} else if (sc->sc_tool_id[1]) {
299 		sc->sc_tool_id[1] = 0;
300 		uwacom_pad_events_graphire4(usbwcmp, 0, 0, 0, 0, 0, 0);
301 	}
302 }
303 
304 static void
uwacom_pos_events_intuos(usbwcm_state_t * usbwcmp,int x,int y,int distance)305 uwacom_pos_events_intuos(usbwcm_state_t *usbwcmp, int x, int y, int distance)
306 {
307 	uwacom_event(usbwcmp, EVT_ABS, ABS_X, x);
308 	uwacom_event(usbwcmp, EVT_ABS, ABS_Y, y);
309 	uwacom_event(usbwcmp, EVT_ABS, ABS_DISTANCE, distance);
310 }
311 
312 static void
uwacom_pen_events_intuos(usbwcm_state_t * usbwcmp,uint8_t * packet)313 uwacom_pen_events_intuos(usbwcm_state_t *usbwcmp, uint8_t *packet)
314 {
315 	struct uwacom_softc *sc = &usbwcmp->usbwcm_softc;
316 	int press, tilt_x, tilt_y, stl1, stl2;
317 
318 	switch (sc->sc_type->protocol) {
319 	case INTUOS4S:
320 	case INTUOS4L:
321 		press = PACKET_BITS(7, 6, 10) << 1 | PACKET_BIT(1, 0);
322 		break;
323 	default:
324 		press = PACKET_BITS(7, 6, 10);
325 		break;
326 	}
327 
328 	tilt_x = PACKET_BITS(8, 7, 7);
329 	tilt_y = PACKET_BITS(8, 0, 7);
330 	stl1 = PACKET_BIT(1, 1);
331 	stl2 = PACKET_BIT(1, 2);
332 
333 	uwacom_event(usbwcmp, EVT_ABS, ABS_PRESSURE, press);
334 	uwacom_event(usbwcmp, EVT_ABS, ABS_TILT_X, tilt_x);
335 	uwacom_event(usbwcmp, EVT_ABS, ABS_TILT_Y, tilt_y);
336 	uwacom_event(usbwcmp, EVT_BTN, BTN_TIP, press);
337 	uwacom_event(usbwcmp, EVT_BTN, BTN_STYLUS_1, stl1);
338 	uwacom_event(usbwcmp, EVT_BTN, BTN_STYLUS_2, stl2);
339 }
340 
341 static void
uwacom_mouse_events_intuos(usbwcm_state_t * usbwcmp,uint8_t * packet)342 uwacom_mouse_events_intuos(usbwcm_state_t *usbwcmp, uint8_t *packet)
343 {
344 	struct uwacom_softc *sc = &usbwcmp->usbwcm_softc;
345 	int left, middle, right, extra, side, wheel;
346 
347 	switch (sc->sc_type->protocol) {
348 	case INTUOS4S:
349 	case INTUOS4L:
350 		left = PACKET_BIT(6, 0);
351 		middle = PACKET_BIT(6, 1);
352 		right = PACKET_BIT(6, 2);
353 		side = PACKET_BIT(6, 3);
354 		extra = PACKET_BIT(6, 4);
355 		wheel = PACKET_BIT(7, 7) - PACKET_BIT(7, 6);
356 		break;
357 
358 	default:
359 		left = PACKET_BIT(8, 2);
360 		middle = PACKET_BIT(8, 3);
361 		right = PACKET_BIT(8, 4);
362 		extra = PACKET_BIT(8, 5);
363 		side = PACKET_BIT(8, 6);
364 		wheel = PACKET_BIT(8, 0) - PACKET_BIT(8, 1);
365 		break;
366 	}
367 
368 	uwacom_event(usbwcmp, EVT_BTN, BTN_LEFT, left);
369 	uwacom_event(usbwcmp, EVT_BTN, BTN_MIDDLE, middle);
370 	uwacom_event(usbwcmp, EVT_BTN, BTN_RIGHT, right);
371 	uwacom_event(usbwcmp, EVT_BTN, BTN_EXTRA, extra);
372 	uwacom_event(usbwcmp, EVT_BTN, BTN_SIDE, side);
373 	uwacom_event(usbwcmp, EVT_REL, REL_WHEEL, wheel);
374 }
375 
376 static void
uwacom_tool_events_intuos(usbwcm_state_t * usbwcmp,int idx,int proximity)377 uwacom_tool_events_intuos(usbwcm_state_t *usbwcmp, int idx, int proximity)
378 {
379 	struct uwacom_softc *sc = &usbwcmp->usbwcm_softc;
380 
381 	uwacom_event(usbwcmp, EVT_BTN, sc->sc_tool[idx], proximity);
382 	uwacom_event(usbwcmp, EVT_ABS, ABS_MISC, sc->sc_tool_id[idx]);
383 	uwacom_event(usbwcmp, EVT_MSC, MSC_SERIAL, sc->sc_serial[idx]);
384 	uwacom_event(usbwcmp, EVT_SYN, SYN_REPORT, 0);
385 }
386 
387 static void
uwacom_pad_events_intuos(usbwcm_state_t * usbwcmp,uint8_t * packet)388 uwacom_pad_events_intuos(usbwcm_state_t *usbwcmp, uint8_t *packet)
389 {
390 	struct uwacom_softc *sc = &usbwcmp->usbwcm_softc;
391 	int b0, b1, b2, b3, b4, b5, b6, b7;
392 	int rx, ry, prox;
393 	int b8, whl, rot;
394 
395 	switch (sc->sc_type->protocol) {
396 	case INTUOS4L:
397 		b7 = PACKET_BIT(3, 6);
398 		b8 = PACKET_BIT(3, 7);
399 
400 		uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_7, b7);
401 		uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_8, b8);
402 	/*FALLTHRU*/
403 	case INTUOS4S:
404 		b0 = PACKET_BIT(2, 0);
405 		b1 = PACKET_BIT(3, 0);
406 		b2 = PACKET_BIT(3, 1);
407 		b3 = PACKET_BIT(3, 2);
408 		b4 = PACKET_BIT(3, 3);
409 		b5 = PACKET_BIT(3, 4);
410 		b6 = PACKET_BIT(3, 5);
411 
412 		uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_0, b0);
413 		uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_1, b1);
414 		uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_2, b2);
415 		uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_3, b3);
416 		uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_4, b4);
417 		uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_5, b5);
418 		uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_6, b6);
419 
420 		whl = PACKET_BIT(1, 7);
421 		if (whl) {
422 			rot = PACKET_BITS(1, 0, 7);
423 			uwacom_event(usbwcmp, EVT_ABS, ABS_WHEEL, rot);
424 		}
425 
426 		prox = b0 | b1 | b2 | b3 | b4 | b5 | b6 | b7 | b8 | whl;
427 		uwacom_tool_events_intuos(usbwcmp, 1, prox);
428 
429 		break;
430 
431 	default:
432 		b0 = PACKET_BIT(5, 0);
433 		b1 = PACKET_BIT(5, 1);
434 		b2 = PACKET_BIT(5, 2);
435 		b3 = PACKET_BIT(5, 3);
436 		b4 = PACKET_BIT(6, 0);
437 		b5 = PACKET_BIT(6, 1);
438 		b6 = PACKET_BIT(6, 2);
439 		b7 = PACKET_BIT(6, 3);
440 		rx = PACKET_BITS(2, 0, 13);
441 		ry = PACKET_BITS(4, 0, 13);
442 
443 		uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_0, b0);
444 		uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_1, b1);
445 		uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_2, b2);
446 		uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_3, b3);
447 		uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_4, b4);
448 		uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_5, b5);
449 		uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_6, b6);
450 		uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_7, b7);
451 		uwacom_event(usbwcmp, EVT_ABS, ABS_RX, rx);
452 		uwacom_event(usbwcmp, EVT_ABS, ABS_RY, ry);
453 
454 		prox = b0 | b1 | b2 | b3 | b4 | b5 | b6 | b7 | rx | ry;
455 		uwacom_tool_events_intuos(usbwcmp, 1, prox);
456 
457 		break;
458 	}
459 }
460 
461 static void
usbwcm_input_intuos(usbwcm_state_t * usbwcmp,mblk_t * mp)462 usbwcm_input_intuos(usbwcm_state_t *usbwcmp, mblk_t *mp)
463 {
464 	struct uwacom_softc *sc = &usbwcmp->usbwcm_softc;
465 	uint8_t *packet = mp->b_rptr;
466 
467 	switch (PACKET_BITS(0, 0, 8)) {
468 	case 0x02:
469 		switch (PACKET_BITS(1, 5, 2)) {
470 		/* Tool entering proximity */
471 		case 0x2:
472 			sc->sc_tool_id[0] = PACKET_BITS(3, 4, 12);
473 			sc->sc_serial[0] =
474 			    (PACKET_BIT(1, 1) ? PACKET_BITS(7, 4, 32) : 0);
475 
476 			switch (sc->sc_tool_id[0]) {
477 			case 0x802: /* Intuos4 Grip Pen */
478 			case 0x804: /* Intuos4 Art Marker */
479 			case 0x823: /* Intuos3 Grip Pen */
480 			case 0x885: /* Intuos3 Art Marker */
481 				sc->sc_tool[0] = BTN_TOOL_PEN;
482 				break;
483 			case 0x80a: /* Intuos4 Grip Pen eraser */
484 			case 0x82b: /* Intuos3 Grip Pen eraser */
485 				sc->sc_tool[0] = BTN_TOOL_ERASER;
486 				break;
487 			case 0x017: /* Intuos3 2D mouse */
488 			case 0x806: /* Intuos4 2D mouse */
489 				sc->sc_tool[0] = BTN_TOOL_MOUSE;
490 				break;
491 			default:
492 				USB_DPRINTF_L1(PRINT_MASK_ALL,
493 				    usbwcm_log_handle,
494 				    "unknown tool ID %03x seen\n",
495 				    sc->sc_tool_id[0]);
496 				sc->sc_tool[0] = BTN_TOOL_PEN;
497 			}
498 			break;
499 
500 		/* Tool leaving proximity */
501 		case 0x0:
502 			uwacom_pos_events_intuos(usbwcmp, 0, 0, 0);
503 
504 			if (sc->sc_tool[0] == BTN_TOOL_MOUSE)
505 				uwacom_mouse_events_intuos(usbwcmp, packet);
506 			else
507 				uwacom_pen_events_intuos(usbwcmp, packet);
508 
509 			sc->sc_tool_id[0] = 0;
510 			uwacom_tool_events_intuos(usbwcmp, 0, 0);
511 			break;
512 
513 		/* Tool motion, outbound */
514 		case 0x1:
515 		/* Outbound tracking is unreliable on the Cintiq */
516 			if (sc->sc_type->protocol == CINTIQ)
517 				break;
518 
519 		/* Tool motion */
520 		/*FALLTHRU*/
521 		case 0x3:
522 			uwacom_pos_events_intuos(usbwcmp,
523 			    (PACKET_BITS(3, 0, 16) << 1) | PACKET_BIT(9, 1),
524 			    (PACKET_BITS(5, 0, 16) << 1) | PACKET_BIT(9, 0),
525 			    PACKET_BITS(9, 2, 6));
526 
527 			if (PACKET_BITS(1, 3, 2) == 0) {
528 				uwacom_pen_events_intuos(usbwcmp, packet);
529 
530 			} else if (PACKET_BITS(1, 1, 4) == 0x5) {
531 				int angle = 450 - PACKET_BITS(7, 6, 10);
532 
533 				if (PACKET_BIT(7, 5)) {
534 					angle = (angle > 0 ? 900 : -900) -
535 					    angle;
536 				}
537 
538 				uwacom_event(usbwcmp, EVT_ABS, ABS_Z, angle);
539 				break;
540 			} else if (PACKET_BITS(1, 1, 4) == 0x8) {
541 				uwacom_mouse_events_intuos(usbwcmp, packet);
542 			} else {
543 				USB_DPRINTF_L1(PRINT_MASK_ALL,
544 				    usbwcm_log_handle,
545 				    "unsupported motion packet type %x "
546 				    "received\n", PACKET_BITS(1, 1, 4));
547 			}
548 
549 			uwacom_tool_events_intuos(usbwcmp, 0, 1);
550 			break;
551 		}
552 
553 		break;
554 
555 	case 0x0c:
556 		uwacom_pad_events_intuos(usbwcmp, packet);
557 		break;
558 
559 	default:
560 		USB_DPRINTF_L1(PRINT_MASK_ALL, usbwcm_log_handle,
561 		    "unknown report type %02x received\n",
562 		    PACKET_BITS(0, 0, 8));
563 	}
564 }
565 
566 static void
uwacom_init_abs(usbwcm_state_t * usbwcmp,int axis,int32_t min,int32_t max,int32_t fuzz,int32_t flat)567 uwacom_init_abs(usbwcm_state_t *usbwcmp, int axis, int32_t min, int32_t max,
568     int32_t fuzz, int32_t flat)
569 {
570 	struct uwacom_softc *sc = &usbwcmp->usbwcm_softc;
571 
572 	sc->sc_abs[axis].min = min;
573 	sc->sc_abs[axis].max = max;
574 	sc->sc_abs[axis].fuzz = fuzz;
575 	sc->sc_abs[axis].flat = flat;
576 }
577 
578 static void
uwacom_init_graphire4(usbwcm_state_t * usbwcmp)579 uwacom_init_graphire4(usbwcm_state_t *usbwcmp)
580 {
581 	struct uwacom_softc *sc = &usbwcmp->usbwcm_softc;
582 
583 	BM_SET_BIT(sc->sc_bm[0], EVT_MSC);
584 	BM_SET_BIT(sc->sc_bm[1], BTN_MISC_0);
585 	BM_SET_BIT(sc->sc_bm[1], BTN_MISC_4);
586 	BM_SET_BIT(sc->sc_bm[1], BTN_TOOL_PAD);
587 	BM_SET_BIT(sc->sc_bm[4], MSC_SERIAL);
588 
589 	sc->sc_tool[1] = BTN_TOOL_PAD;
590 	sc->sc_serial[1] = SERIAL_PAD_GRAPHIRE4;
591 }
592 
593 static void
uwacom_init_myoffice(usbwcm_state_t * usbwcmp)594 uwacom_init_myoffice(usbwcm_state_t *usbwcmp)
595 {
596 	struct uwacom_softc *sc = &usbwcmp->usbwcm_softc;
597 
598 	BM_SET_BIT(sc->sc_bm[1], BTN_MISC_1);
599 	BM_SET_BIT(sc->sc_bm[1], BTN_MISC_5);
600 	BM_SET_BIT(sc->sc_bm[3], ABS_WHEEL);
601 
602 	uwacom_init_abs(usbwcmp, ABS_WHEEL, 0, 71, 0, 0);
603 }
604 
605 static void
uwacom_init_intuos(usbwcm_state_t * usbwcmp)606 uwacom_init_intuos(usbwcm_state_t *usbwcmp)
607 {
608 	struct uwacom_softc *sc = &usbwcmp->usbwcm_softc;
609 
610 	BM_SET_BIT(sc->sc_bm[0], EVT_MSC);
611 
612 	BM_SET_BIT(sc->sc_bm[1], BTN_MISC_0);
613 	BM_SET_BIT(sc->sc_bm[1], BTN_MISC_1);
614 	BM_SET_BIT(sc->sc_bm[1], BTN_MISC_2);
615 	BM_SET_BIT(sc->sc_bm[1], BTN_MISC_3);
616 	BM_SET_BIT(sc->sc_bm[1], BTN_SIDE);
617 	BM_SET_BIT(sc->sc_bm[1], BTN_EXTRA);
618 	BM_SET_BIT(sc->sc_bm[1], BTN_TOOL_PAD);
619 
620 	BM_SET_BIT(sc->sc_bm[3], ABS_TILT_X);
621 	BM_SET_BIT(sc->sc_bm[3], ABS_TILT_Y);
622 
623 	BM_SET_BIT(sc->sc_bm[4], MSC_SERIAL);
624 
625 	sc->sc_tool[1] = BTN_TOOL_PAD;
626 	sc->sc_tool_id[1] = TOOL_ID_PAD;
627 	sc->sc_serial[1] = SERIAL_PAD_INTUOS;
628 }
629 
630 static void
uwacom_init_intuos3(usbwcm_state_t * usbwcmp)631 uwacom_init_intuos3(usbwcm_state_t *usbwcmp)
632 {
633 	struct uwacom_softc *sc = &usbwcmp->usbwcm_softc;
634 
635 	BM_SET_BIT(sc->sc_bm[3], ABS_Z);
636 	BM_SET_BIT(sc->sc_bm[3], ABS_RX);
637 
638 	uwacom_init_abs(usbwcmp, ABS_Z, -900,  899, 0, 0);
639 	uwacom_init_abs(usbwcmp, ABS_RX, 0, 4096, 0, 0);
640 }
641 
642 static void
uwacom_init_intuos3_large(usbwcm_state_t * usbwcmp)643 uwacom_init_intuos3_large(usbwcm_state_t *usbwcmp)
644 {
645 	struct uwacom_softc *sc = &usbwcmp->usbwcm_softc;
646 
647 	BM_SET_BIT(sc->sc_bm[1], BTN_MISC_4);
648 	BM_SET_BIT(sc->sc_bm[1], BTN_MISC_5);
649 	BM_SET_BIT(sc->sc_bm[1], BTN_MISC_6);
650 	BM_SET_BIT(sc->sc_bm[1], BTN_MISC_7);
651 
652 	BM_SET_BIT(sc->sc_bm[3], ABS_RY);
653 
654 	uwacom_init_abs(usbwcmp, ABS_RY, 0, 4096, 0, 0);
655 }
656 
657 static void
uwacom_init_intuos4(usbwcm_state_t * usbwcmp)658 uwacom_init_intuos4(usbwcm_state_t *usbwcmp)
659 {
660 	struct uwacom_softc *sc = &usbwcmp->usbwcm_softc;
661 
662 	BM_SET_BIT(sc->sc_bm[1], BTN_MISC_4);
663 	BM_SET_BIT(sc->sc_bm[1], BTN_MISC_5);
664 	BM_SET_BIT(sc->sc_bm[1], BTN_MISC_6);
665 
666 	BM_SET_BIT(sc->sc_bm[3], ABS_Z);
667 
668 	uwacom_init_abs(usbwcmp, ABS_Z, -900,  899, 0, 0);
669 }
670 static void
uwacom_init_intuos4_large(usbwcm_state_t * usbwcmp)671 uwacom_init_intuos4_large(usbwcm_state_t *usbwcmp)
672 {
673 	struct uwacom_softc *sc = &usbwcmp->usbwcm_softc;
674 
675 	BM_SET_BIT(sc->sc_bm[1], BTN_MISC_7);
676 	BM_SET_BIT(sc->sc_bm[1], BTN_MISC_8);
677 }
678 
679 static int
uwacom_init(usbwcm_state_t * usbwcmp)680 uwacom_init(usbwcm_state_t *usbwcmp)
681 {
682 	struct uwacom_softc *sc = &usbwcmp->usbwcm_softc;
683 
684 	sc->sc_id.bus = ID_BUS_USB;
685 	sc->sc_id.vendor = usbwcmp->usbwcm_devid.VendorId;
686 	sc->sc_id.product = usbwcmp->usbwcm_devid.ProductId;
687 
688 	sc->sc_id.version = 0;
689 
690 	for (int i = 0; i < EVT_USED; ++i)
691 		sc->sc_bm[i] = kmem_zalloc(bm_size[i], KM_SLEEP);
692 
693 	sc->sc_btn = kmem_zalloc(BTN_USED * sizeof (int), KM_SLEEP);
694 	sc->sc_abs = kmem_zalloc(ABS_USED * sizeof (struct event_abs_axis),
695 	    KM_SLEEP);
696 
697 	BM_SET_BIT(sc->sc_bm[0], EVT_SYN);
698 	BM_SET_BIT(sc->sc_bm[0], EVT_BTN);
699 	BM_SET_BIT(sc->sc_bm[0], EVT_REL);
700 	BM_SET_BIT(sc->sc_bm[0], EVT_ABS);
701 
702 	BM_SET_BIT(sc->sc_bm[1], BTN_LEFT);
703 	BM_SET_BIT(sc->sc_bm[1], BTN_RIGHT);
704 	BM_SET_BIT(sc->sc_bm[1], BTN_MIDDLE);
705 	BM_SET_BIT(sc->sc_bm[1], BTN_TOOL_PEN);
706 	BM_SET_BIT(sc->sc_bm[1], BTN_TOOL_ERASER);
707 	BM_SET_BIT(sc->sc_bm[1], BTN_TOOL_MOUSE);
708 	BM_SET_BIT(sc->sc_bm[1], BTN_TIP);
709 	BM_SET_BIT(sc->sc_bm[1], BTN_STYLUS_1);
710 	BM_SET_BIT(sc->sc_bm[1], BTN_STYLUS_2);
711 
712 	BM_SET_BIT(sc->sc_bm[2], REL_WHEEL);
713 
714 	BM_SET_BIT(sc->sc_bm[3], ABS_X);
715 	BM_SET_BIT(sc->sc_bm[3], ABS_Y);
716 	BM_SET_BIT(sc->sc_bm[3], ABS_PRESSURE);
717 	BM_SET_BIT(sc->sc_bm[3], ABS_DISTANCE);
718 	BM_SET_BIT(sc->sc_bm[3], ABS_MISC);
719 
720 	uwacom_init_abs(usbwcmp, ABS_X, 0, sc->sc_type->x_max, 4, 0);
721 	uwacom_init_abs(usbwcmp, ABS_Y, 0, sc->sc_type->y_max, 4, 0);
722 	uwacom_init_abs(usbwcmp, ABS_PRESSURE, 0, sc->sc_type->pressure_max,
723 	    0, 0);
724 	uwacom_init_abs(usbwcmp, ABS_DISTANCE, 0,
725 	    uwacom_protocols[sc->sc_type->protocol].distance_max, 0, 0);
726 
727 	switch (sc->sc_type->protocol) {
728 		case CINTIQ:
729 		case INTUOS3L:
730 			uwacom_init_intuos3_large(usbwcmp);
731 		/*FALLTHRU*/
732 		case INTUOS3S:
733 			uwacom_init_intuos3(usbwcmp);
734 			uwacom_init_intuos(usbwcmp);
735 			break;
736 
737 		case INTUOS4L:
738 			uwacom_init_intuos4_large(usbwcmp);
739 		/*FALLTHRU*/
740 		case INTUOS4S:
741 			uwacom_init_intuos4(usbwcmp);
742 			uwacom_init_intuos(usbwcmp);
743 			break;
744 		case MYOFFICE:
745 			uwacom_init_myoffice(usbwcmp);
746 		/*FALLTHRU*/
747 		case GRAPHIRE4:
748 			uwacom_init_graphire4(usbwcmp);
749 		/*FALLTHRU*/
750 		case GRAPHIRE:
751 			break;
752 	}
753 
754 	return (0);
755 }
756 
757 /*
758  * usbwcm_match() :
759  *	Match device with it's parameters.
760  */
761 static const struct uwacom_type *
usbwcm_match(uint16_t vid,uint16_t pid)762 usbwcm_match(uint16_t vid, uint16_t pid)
763 {
764 	const struct uwacom_type *dev;
765 
766 	dev = uwacom_devs;
767 	while (dev->devno.vid != 0 && dev->devno.pid != 0) {
768 		if (dev->devno.vid == vid && dev->devno.pid == pid) {
769 			return (dev);
770 		}
771 		dev++;
772 	}
773 
774 	return (NULL);
775 }
776 
777 /*
778  * usbwcm_probe() :
779  *	Check the device type and protocol.
780  */
781 static int
usbwcm_probe(usbwcm_state_t * usbwcmp)782 usbwcm_probe(usbwcm_state_t *usbwcmp)
783 {
784 	queue_t		*q = usbwcmp->usbwcm_rq;
785 	mblk_t		*mctl_ptr;
786 	struct iocblk	mctlmsg;
787 	hid_req_t	*featr;
788 
789 	/* check device IDs */
790 	mctlmsg.ioc_cmd = HID_GET_VID_PID;
791 	mctlmsg.ioc_count = 0;
792 
793 	mctl_ptr = usba_mk_mctl(mctlmsg, NULL, 0);
794 	if (mctl_ptr == NULL) {
795 		return (ENOMEM);
796 	}
797 
798 	putnext(usbwcmp->usbwcm_wq, mctl_ptr);
799 	usbwcmp->usbwcm_flags |= USBWCM_QWAIT;
800 
801 	while (usbwcmp->usbwcm_flags & USBWCM_QWAIT) {
802 		if (qwait_sig(q) == 0) {
803 			usbwcmp->usbwcm_flags = 0;
804 			return (EINTR);
805 		}
806 	}
807 
808 	usbwcmp->usbwcm_softc.sc_type =
809 	    usbwcm_match(usbwcmp->usbwcm_devid.VendorId,
810 	    usbwcmp->usbwcm_devid.ProductId);
811 	if (!usbwcmp->usbwcm_softc.sc_type) {
812 		USB_DPRINTF_L1(PRINT_MASK_ALL, usbwcm_log_handle,
813 		    "unsupported tablet model\n");
814 		return (ENXIO);
815 	}
816 
817 	if (uwacom_init(usbwcmp) != 0) {
818 		return (ENXIO);
819 	}
820 
821 	/* set feature: tablet mode */
822 	featr = kmem_zalloc(sizeof (hid_req_t), KM_SLEEP);
823 	featr->hid_req_version_no = HID_VERSION_V_0;
824 	featr->hid_req_wValue = REPORT_TYPE_FEATURE | 2;
825 	featr->hid_req_wLength = sizeof (uint8_t) * 2;
826 	featr->hid_req_data[0] = 2;
827 	featr->hid_req_data[1] = 2;
828 
829 	mctlmsg.ioc_cmd = HID_SET_REPORT;
830 	mctlmsg.ioc_count = sizeof (featr);
831 	mctl_ptr = usba_mk_mctl(mctlmsg, featr, sizeof (hid_req_t));
832 	if (mctl_ptr != NULL) {
833 		putnext(usbwcmp->usbwcm_wq, mctl_ptr);
834 
835 		/*
836 		 * Waiting for response of HID_SET_REPORT
837 		 * mctl for setting the feature.
838 		 */
839 		usbwcmp->usbwcm_flags |= USBWCM_QWAIT;
840 		while (usbwcmp->usbwcm_flags & USBWCM_QWAIT) {
841 			qwait(q);
842 		}
843 	} else {
844 		USB_DPRINTF_L1(PRINT_MASK_ALL, usbwcm_log_handle,
845 		    "enable tablet mode failed\n");
846 	}
847 
848 	kmem_free(featr, sizeof (hid_req_t));
849 
850 	return (0);
851 }
852 
853 /*
854  * usbwcm_copyreq() :
855  *	helper function for usbwcm ioctls
856  */
857 static int
usbwcm_copyreq(mblk_t * mp,uint_t pvtsize,uint_t state,uint_t reqsize,uint_t contsize,uint_t copytype)858 usbwcm_copyreq(mblk_t *mp, uint_t pvtsize, uint_t state, uint_t reqsize,
859     uint_t contsize, uint_t copytype)
860 {
861 	usbwcm_copyin_t	*copystat;
862 	mblk_t		*iocmp, *contmp;
863 	struct copyreq	*cq;
864 	struct copyresp	*cr;
865 
866 	if ((pvtsize == 0) && (state != 0)) {
867 		cr = (struct copyresp *)mp->b_rptr;
868 		iocmp = cr->cp_private;
869 	}
870 
871 	cq = (struct copyreq *)mp->b_rptr;
872 	if (mp->b_cont == NULL) {
873 
874 		return (EINVAL);
875 	}
876 
877 	cq->cq_addr = *((caddr_t *)mp->b_cont->b_rptr);
878 	cq->cq_size = reqsize;
879 	cq->cq_flag = 0;
880 
881 	if (pvtsize) {
882 		iocmp = (mblk_t *)allocb(pvtsize, BPRI_MED);
883 		if (iocmp == NULL) {
884 
885 			return (EAGAIN);
886 		}
887 		cq->cq_private = iocmp;
888 		iocmp = cq->cq_private;
889 	} else {
890 		/*
891 		 * Here we need to set cq_private even if there's
892 		 * no private data, otherwise its value will be
893 		 * TRANSPARENT (-1) on 64bit systems because it
894 		 * overlaps iocp->ioc_count. If user address (cq_addr)
895 		 * is invalid, it would cause panic later in
896 		 * usbwcm_copyin:
897 		 *	freemsg((mblk_t *)copyresp->cp_private);
898 		 */
899 		cq->cq_private = NULL;
900 	}
901 
902 	if (state) {
903 		copystat = (usbwcm_copyin_t *)iocmp->b_rptr;
904 		copystat->state = state;
905 		if (pvtsize) {  /* M_COPYIN */
906 			copystat->addr = cq->cq_addr;
907 		} else {
908 			cq->cq_addr = copystat->addr;
909 			cq->cq_private = iocmp;
910 		}
911 		iocmp->b_wptr = iocmp->b_rptr + sizeof (usbwcm_copyin_t);
912 	}
913 
914 	if (contsize) {
915 		contmp = (mblk_t *)allocb(contsize, BPRI_MED);
916 		if (contmp == NULL) {
917 
918 			return (EAGAIN);
919 		}
920 		if (mp->b_cont) {
921 			freemsg(mp->b_cont);
922 			mp->b_cont = contmp;
923 		}
924 	}
925 
926 	mp->b_datap->db_type = (unsigned char)copytype;
927 	mp->b_wptr = mp->b_rptr + sizeof (struct copyreq);
928 
929 	return (0);
930 }
931 
932 static void
usbwcm_miocack(queue_t * q,mblk_t * mp,int rval)933 usbwcm_miocack(queue_t *q, mblk_t *mp, int rval)
934 {
935 	struct iocblk	*iocbp = (struct iocblk *)mp->b_rptr;
936 
937 	mp->b_datap->db_type = M_IOCACK;
938 	mp->b_wptr = mp->b_rptr + sizeof (struct iocblk);
939 
940 	iocbp->ioc_error = 0;
941 	iocbp->ioc_count = 0;
942 	iocbp->ioc_rval = rval;
943 
944 	if (mp->b_cont != NULL) {
945 		freemsg(mp->b_cont);
946 		mp->b_cont = NULL;
947 	}
948 
949 	qreply(q, mp);
950 }
951 
952 /*
953  * usbwcm_iocpy() :
954  * M_IOCDATA processing for IOCTL's
955  */
956 static void
usbwcm_iocpy(queue_t * q,mblk_t * mp)957 usbwcm_iocpy(queue_t *q, mblk_t *mp)
958 {
959 	usbwcm_state_t		*usbwcmp = (usbwcm_state_t *)q->q_ptr;
960 	struct uwacom_softc	*sc = &usbwcmp->usbwcm_softc;
961 	struct copyresp		*copyresp;
962 	usbwcm_copyin_t		*copystat;
963 	mblk_t			*datap, *ioctmp;
964 	struct iocblk		*iocbp;
965 	int			err = 0;
966 
967 	copyresp = (struct copyresp *)mp->b_rptr;
968 	iocbp = (struct iocblk *)mp->b_rptr;
969 	if (copyresp->cp_rval) {
970 		err = EAGAIN;
971 
972 		goto out;
973 	}
974 
975 	switch (copyresp->cp_cmd) {
976 	default: {
977 		int num = copyresp->cp_cmd & 0xff;
978 		int len = IOCPARM_MASK & (copyresp->cp_cmd >> 16);
979 
980 		if (((copyresp->cp_cmd >> 8) & 0xFF) != 'E') {
981 			putnext(q, mp); /* pass it down the line */
982 			return;
983 
984 		} else if ((copyresp->cp_cmd & IOC_INOUT) != IOC_OUT) {
985 			err = EINVAL;
986 			break;
987 		}
988 
989 		switch (num) {
990 		case EUWACOMGETVERSION:
991 			ioctmp = copyresp->cp_private;
992 			copystat = (usbwcm_copyin_t *)ioctmp->b_rptr;
993 			if (copystat->state == USBWCM_GETSTRUCT) {
994 				if (mp->b_cont == NULL) {
995 					err = EINVAL;
996 
997 					break;
998 				}
999 				datap = (mblk_t *)mp->b_cont;
1000 
1001 				*(int *)datap->b_rptr = 0x00010000;
1002 
1003 				if (err = usbwcm_copyreq(mp, 0,
1004 				    USBWCM_GETRESULT, sizeof (int), 0,
1005 				    M_COPYOUT)) {
1006 
1007 					goto out;
1008 				}
1009 			} else if (copystat->state == USBWCM_GETRESULT) {
1010 				freemsg(ioctmp);
1011 				usbwcm_miocack(q, mp, 0);
1012 				return;
1013 			}
1014 			break;
1015 
1016 		case EUWACOMGETID:
1017 			ioctmp = copyresp->cp_private;
1018 			copystat = (usbwcm_copyin_t *)ioctmp->b_rptr;
1019 			if (copystat->state == USBWCM_GETSTRUCT) {
1020 				if (mp->b_cont == NULL) {
1021 					err = EINVAL;
1022 
1023 					break;
1024 				}
1025 				datap = (mblk_t *)mp->b_cont;
1026 
1027 				bcopy(&sc->sc_id, datap->b_rptr,
1028 				    sizeof (struct event_dev_id));
1029 
1030 				if (err = usbwcm_copyreq(mp, 0,
1031 				    USBWCM_GETRESULT,
1032 				    sizeof (struct event_dev_id), 0,
1033 				    M_COPYOUT)) {
1034 
1035 					goto out;
1036 				}
1037 			} else if (copystat->state == USBWCM_GETRESULT) {
1038 				freemsg(ioctmp);
1039 				usbwcm_miocack(q, mp, 0);
1040 				return;
1041 			}
1042 			break;
1043 
1044 		default:
1045 			if (num >= EUWACOMGETBM &&
1046 			    num < EUWACOMGETBM + EVT_USED) {
1047 				int idx = num - EUWACOMGETBM;
1048 				size_t length = min(bm_size[idx], len);
1049 
1050 				ioctmp = copyresp->cp_private;
1051 				copystat = (usbwcm_copyin_t *)ioctmp->b_rptr;
1052 				if (copystat->state == USBWCM_GETSTRUCT) {
1053 					if (mp->b_cont == NULL) {
1054 						err = EINVAL;
1055 
1056 						break;
1057 					}
1058 					datap = (mblk_t *)mp->b_cont;
1059 
1060 					bcopy(sc->sc_bm[idx], datap->b_rptr,
1061 					    length);
1062 
1063 					if (err = usbwcm_copyreq(mp, 0,
1064 					    USBWCM_GETRESULT, length, 0,
1065 					    M_COPYOUT)) {
1066 
1067 						goto out;
1068 					}
1069 
1070 				} else if (copystat->state ==
1071 				    USBWCM_GETRESULT) {
1072 					freemsg(ioctmp);
1073 					usbwcm_miocack(q, mp, length);
1074 					return;
1075 				}
1076 				break;
1077 
1078 			} else if (num >= EUWACOMGETABS &&
1079 			    num < EUWACOMGETABS + ABS_USED) {
1080 				int idx = num - EUWACOMGETABS;
1081 
1082 				ioctmp = copyresp->cp_private;
1083 				copystat = (usbwcm_copyin_t *)ioctmp->b_rptr;
1084 				if (copystat->state == USBWCM_GETSTRUCT) {
1085 					if (mp->b_cont == NULL) {
1086 						err = EINVAL;
1087 
1088 						break;
1089 					}
1090 					datap = (mblk_t *)mp->b_cont;
1091 
1092 					bcopy(&sc->sc_abs[idx], datap->b_rptr,
1093 					    sizeof (struct event_abs_axis));
1094 
1095 					if (err = usbwcm_copyreq(mp, 0,
1096 					    USBWCM_GETRESULT,
1097 					    sizeof (struct event_abs_axis), 0,
1098 					    M_COPYOUT)) {
1099 
1100 						goto out;
1101 					}
1102 
1103 				} else if (copystat->state ==
1104 				    USBWCM_GETRESULT) {
1105 					freemsg(ioctmp);
1106 					usbwcm_miocack(q, mp, 0);
1107 					return;
1108 				}
1109 				break;
1110 
1111 			} else {
1112 				err = EINVAL;
1113 				break;
1114 			}
1115 		}
1116 	}
1117 	}
1118 
1119 out:
1120 	if (err) {
1121 		mp->b_datap->db_type = M_IOCNAK;
1122 		if (mp->b_cont) {
1123 			freemsg(mp->b_cont);
1124 			mp->b_cont = (mblk_t *)NULL;
1125 		}
1126 		if (copyresp->cp_private) {
1127 			freemsg((mblk_t *)copyresp->cp_private);
1128 			copyresp->cp_private = (mblk_t *)NULL;
1129 		}
1130 		iocbp->ioc_count = 0;
1131 		iocbp->ioc_error = err;
1132 	}
1133 
1134 	qreply(q, mp);
1135 }
1136 
1137 /*
1138  * usbwcm_ioctl() :
1139  *	Process ioctls we recognize and own.  Otherwise, NAK.
1140  */
1141 static void
usbwcm_ioctl(queue_t * q,mblk_t * mp)1142 usbwcm_ioctl(queue_t *q, mblk_t *mp)
1143 {
1144 	usbwcm_state_t		*usbwcmp = (usbwcm_state_t *)q->q_ptr;
1145 	struct uwacom_softc	*sc;
1146 	mblk_t			*datap;
1147 	struct iocblk		*iocp;
1148 	int			err = 0;
1149 
1150 	if (usbwcmp == NULL) {
1151 		miocnak(q, mp, 0, EINVAL);
1152 		return;
1153 	}
1154 
1155 	sc = &usbwcmp->usbwcm_softc;
1156 	iocp = (struct iocblk *)mp->b_rptr;
1157 
1158 	switch (iocp->ioc_cmd) {
1159 	default: {
1160 		int num = iocp->ioc_cmd & 0xff;
1161 		int len = IOCPARM_MASK & (iocp->ioc_cmd >> 16);
1162 
1163 		if (((iocp->ioc_cmd >> 8) & 0xFF) != 'E') {
1164 			putnext(q, mp); /* pass it down the line */
1165 			return;
1166 
1167 		} else if ((iocp->ioc_cmd & IOC_INOUT) != IOC_OUT) {
1168 			err = EINVAL;
1169 			break;
1170 		}
1171 
1172 		switch (num) {
1173 		case EUWACOMGETVERSION:
1174 			if (iocp->ioc_count == TRANSPARENT) {
1175 				if (err = usbwcm_copyreq(mp,
1176 				    sizeof (usbwcm_copyin_t), USBWCM_GETSTRUCT,
1177 				    sizeof (int), 0, M_COPYIN)) {
1178 					break;
1179 				}
1180 				freemsg(mp->b_cont);
1181 				mp->b_cont = (mblk_t *)NULL;
1182 
1183 				qreply(q, mp);
1184 				return;
1185 			}
1186 
1187 			if (mp->b_cont == NULL ||
1188 			    iocp->ioc_count != sizeof (int)) {
1189 				err = EINVAL;
1190 				break;
1191 			}
1192 			datap = mp->b_cont;
1193 
1194 			*(int *)datap->b_rptr = 0x00010000;
1195 
1196 			break;
1197 
1198 		case EUWACOMGETID:
1199 			if (iocp->ioc_count == TRANSPARENT) {
1200 				if (err = usbwcm_copyreq(mp,
1201 				    sizeof (usbwcm_copyin_t), USBWCM_GETSTRUCT,
1202 				    sizeof (struct event_dev_id), 0,
1203 				    M_COPYIN)) {
1204 					break;
1205 				}
1206 				freemsg(mp->b_cont);
1207 				mp->b_cont = (mblk_t *)NULL;
1208 
1209 				qreply(q, mp);
1210 				return;
1211 			}
1212 
1213 			if (mp->b_cont == NULL ||
1214 			    iocp->ioc_count != sizeof (struct event_dev_id)) {
1215 				err = EINVAL;
1216 				break;
1217 			}
1218 			datap = mp->b_cont;
1219 
1220 			bcopy(&sc->sc_id, datap->b_rptr,
1221 			    sizeof (struct event_dev_id));
1222 
1223 			break;
1224 
1225 		default:
1226 			if (num >= EUWACOMGETBM &&
1227 			    num < EUWACOMGETBM + EVT_USED) {
1228 				int idx = num - EUWACOMGETBM;
1229 				size_t length = min(bm_size[idx], len);
1230 
1231 				if (iocp->ioc_count == TRANSPARENT) {
1232 					if (err = usbwcm_copyreq(mp,
1233 					    sizeof (usbwcm_copyin_t),
1234 					    USBWCM_GETSTRUCT, length, 0,
1235 					    M_COPYIN)) {
1236 						break;
1237 					}
1238 					freemsg(mp->b_cont);
1239 					mp->b_cont = (mblk_t *)NULL;
1240 
1241 					qreply(q, mp);
1242 					return;
1243 				}
1244 
1245 				if (mp->b_cont == NULL ||
1246 				    iocp->ioc_count != length) {
1247 					err = EINVAL;
1248 					break;
1249 				}
1250 				datap = mp->b_cont;
1251 
1252 				bcopy(sc->sc_bm[idx], datap->b_rptr, length);
1253 
1254 				break;
1255 
1256 			} else if (num >= EUWACOMGETABS &&
1257 			    num < EUWACOMGETABS + ABS_USED) {
1258 				int idx = num - EUWACOMGETABS;
1259 
1260 				if (iocp->ioc_count == TRANSPARENT) {
1261 					if (err = usbwcm_copyreq(mp,
1262 					    sizeof (usbwcm_copyin_t),
1263 					    USBWCM_GETSTRUCT,
1264 					    sizeof (struct event_abs_axis), 0,
1265 					    M_COPYIN)) {
1266 						break;
1267 					}
1268 					freemsg(mp->b_cont);
1269 					mp->b_cont = (mblk_t *)NULL;
1270 
1271 					qreply(q, mp);
1272 					return;
1273 				}
1274 
1275 				if (mp->b_cont == NULL ||
1276 				    iocp->ioc_count !=
1277 				    sizeof (struct event_abs_axis)) {
1278 					err = EINVAL;
1279 					break;
1280 				}
1281 				datap = mp->b_cont;
1282 
1283 				bcopy(&sc->sc_abs[idx], datap->b_rptr,
1284 				    sizeof (struct event_abs_axis));
1285 
1286 				break;
1287 
1288 			} else {
1289 				err = EINVAL;
1290 				break;
1291 			}
1292 		}
1293 	}
1294 	}
1295 
1296 	if (err != 0)
1297 		miocnak(q, mp, 0, err);
1298 	else {
1299 		iocp->ioc_rval = 0;
1300 		iocp->ioc_error = 0;
1301 		mp->b_datap->db_type = M_IOCACK;
1302 		qreply(q, mp);
1303 		/* REMOVE */
1304 	}
1305 
1306 	return;
1307 
1308 }
1309 
1310 /*
1311  * usbwcm_input() :
1312  *
1313  *	Wacom input routine; process data received from a device and
1314  *	assemble into a input event for the window system.
1315  *
1316  *	Watch out for overflow!
1317  */
1318 static void
usbwcm_input(usbwcm_state_t * usbwcmp,mblk_t * mp)1319 usbwcm_input(usbwcm_state_t *usbwcmp, mblk_t *mp)
1320 {
1321 	struct uwacom_softc	*sc = &usbwcmp->usbwcm_softc;
1322 
1323 	switch (sc->sc_type->protocol) {
1324 	case GRAPHIRE:
1325 	case GRAPHIRE4:
1326 	case MYOFFICE:
1327 		usbwcm_input_graphire(usbwcmp, mp);
1328 		break;
1329 
1330 	case INTUOS3S:
1331 	case INTUOS3L:
1332 	case INTUOS4S:
1333 	case INTUOS4L:
1334 	case CINTIQ:
1335 		usbwcm_input_intuos(usbwcmp, mp);
1336 		break;
1337 	}
1338 }
1339 
1340 /*
1341  * usbwcm_flush() :
1342  *	Resets the soft state to default values
1343  *	and sends M_FLUSH above.
1344  */
1345 static void
usbwcm_flush(usbwcm_state_t * usbwcmp)1346 usbwcm_flush(usbwcm_state_t *usbwcmp)
1347 {
1348 	queue_t			*q;
1349 
1350 	if ((q = usbwcmp->usbwcm_rq) != NULL && q->q_next != NULL) {
1351 		(void) putnextctl1(q, M_FLUSH, FLUSHR);
1352 	}
1353 }
1354 
1355 /*
1356  * usbwcm_mctl() :
1357  *	Handle M_CTL messages from hid.  If
1358  *	we don't understand the command, free message.
1359  */
1360 static void
usbwcm_mctl(queue_t * q,mblk_t * mp)1361 usbwcm_mctl(queue_t *q, mblk_t *mp)
1362 {
1363 	usbwcm_state_t	*usbwcmp = (usbwcm_state_t *)q->q_ptr;
1364 	struct iocblk	*iocp;
1365 	caddr_t		data = NULL;
1366 	struct iocblk	mctlmsg;
1367 	mblk_t		*mctl_ptr;
1368 	hid_req_t	*featr;
1369 
1370 	iocp = (struct iocblk *)mp->b_rptr;
1371 	if (mp->b_cont != NULL)
1372 		data = (caddr_t)mp->b_cont->b_rptr;
1373 
1374 	switch (iocp->ioc_cmd) {
1375 	case HID_GET_VID_PID:
1376 		if ((data != NULL) &&
1377 		    (iocp->ioc_count == sizeof (hid_vid_pid_t)) &&
1378 		    (MBLKL(mp->b_cont) == iocp->ioc_count)) {
1379 			bcopy(data, &usbwcmp->usbwcm_devid, iocp->ioc_count);
1380 		}
1381 
1382 		freemsg(mp);
1383 		usbwcmp->usbwcm_flags &= ~USBWCM_QWAIT;
1384 		break;
1385 
1386 	case HID_CONNECT_EVENT:
1387 		/* set feature: tablet mode */
1388 		featr = kmem_zalloc(sizeof (hid_req_t), KM_SLEEP);
1389 		featr->hid_req_version_no = HID_VERSION_V_0;
1390 		featr->hid_req_wValue = REPORT_TYPE_FEATURE | 2;
1391 		featr->hid_req_wLength = sizeof (uint8_t) * 2;
1392 		featr->hid_req_data[0] = 2;
1393 		featr->hid_req_data[1] = 2;
1394 
1395 		mctlmsg.ioc_cmd = HID_SET_REPORT;
1396 		mctlmsg.ioc_count = sizeof (featr);
1397 		mctl_ptr = usba_mk_mctl(mctlmsg, featr, sizeof (hid_req_t));
1398 		if (mctl_ptr != NULL) {
1399 			putnext(usbwcmp->usbwcm_wq, mctl_ptr);
1400 		} else {
1401 		USB_DPRINTF_L1(PRINT_MASK_ALL, usbwcm_log_handle,
1402 		    "enable tablet mode failed\n");
1403 		}
1404 
1405 		kmem_free(featr, sizeof (hid_req_t));
1406 		freemsg(mp);
1407 		break;
1408 
1409 	case HID_SET_REPORT:
1410 		/* FALLTHRU */
1411 
1412 	case HID_SET_PROTOCOL:
1413 		usbwcmp->usbwcm_flags &= ~USBWCM_QWAIT;
1414 		/* FALLTHRU */
1415 
1416 	default:
1417 		freemsg(mp);
1418 	}
1419 }
1420 
1421 /*
1422  * usbwcm_open() :
1423  *	open() entry point for the USB wacom module.
1424  */
1425 /*ARGSUSED*/
1426 static int
usbwcm_open(queue_t * q,dev_t * devp,int flag,int sflag,cred_t * credp)1427 usbwcm_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
1428 {
1429 	usbwcm_state_t	*usbwcmp;
1430 
1431 	/* Clone opens are not allowed */
1432 	if (sflag != MODOPEN)
1433 		return (EINVAL);
1434 
1435 	/* If the module is already open, just return */
1436 	if (q->q_ptr) {
1437 		return (0);
1438 	}
1439 
1440 	/* allocate usbwcm state structure */
1441 	usbwcmp = kmem_zalloc(sizeof (usbwcm_state_t), KM_SLEEP);
1442 
1443 	q->q_ptr = usbwcmp;
1444 	WR(q)->q_ptr = usbwcmp;
1445 
1446 	usbwcmp->usbwcm_rq = q;
1447 	usbwcmp->usbwcm_wq = WR(q);
1448 
1449 	qprocson(q);
1450 
1451 	if (usbwcm_probe(usbwcmp) != 0) {
1452 
1453 		qprocsoff(q);
1454 		kmem_free(usbwcmp, sizeof (usbwcm_state_t));
1455 
1456 		return (EINVAL);
1457 	}
1458 
1459 	usbwcm_flush(usbwcmp);
1460 
1461 	usbwcmp->usbwcm_flags |= USBWCM_OPEN;
1462 	return (0);
1463 }
1464 
1465 
1466 /*
1467  * usbwcm_close() :
1468  *	close() entry point for the USB wacom module.
1469  */
1470 /*ARGSUSED*/
1471 static int
usbwcm_close(queue_t * q,int flag,cred_t * credp)1472 usbwcm_close(queue_t *q, int flag, cred_t *credp)
1473 {
1474 	usbwcm_state_t		*usbwcmp = q->q_ptr;
1475 	struct uwacom_softc	*sc = &usbwcmp->usbwcm_softc;
1476 
1477 	qprocsoff(q);
1478 
1479 	if (usbwcmp->usbwcm_bufcall) {
1480 		qunbufcall(q, (bufcall_id_t)(long)usbwcmp->usbwcm_bufcall);
1481 		usbwcmp->usbwcm_bufcall = 0;
1482 	}
1483 
1484 	if (usbwcmp->usbwcm_mioctl != NULL) {
1485 		/*
1486 		 * We were holding an "ioctl" response pending the
1487 		 * availability of an "mblk" to hold data to be passed up;
1488 		 * another "ioctl" came through, which means that "ioctl"
1489 		 * must have timed out or been aborted.
1490 		 */
1491 		freemsg(usbwcmp->usbwcm_mioctl);
1492 		usbwcmp->usbwcm_mioctl = NULL;
1493 	}
1494 
1495 	for (int i = 0; i < EVT_USED; i++)
1496 		kmem_free(sc->sc_bm[i], bm_size[i]);
1497 
1498 	kmem_free(sc->sc_btn, BTN_USED * sizeof (int));
1499 	kmem_free(sc->sc_abs, ABS_USED * sizeof (struct event_abs_axis));
1500 	kmem_free(usbwcmp, sizeof (usbwcm_state_t));
1501 
1502 	q->q_ptr = WR(q)->q_ptr = NULL;
1503 	return (0);
1504 }
1505 
1506 /*
1507  * usbwcm_wput() :
1508  *	wput() routine for the wacom module.
1509  *	Module below : hid, module above : consms
1510  */
1511 static int
usbwcm_wput(queue_t * q,mblk_t * mp)1512 usbwcm_wput(queue_t *q, mblk_t *mp)
1513 {
1514 	switch (mp->b_datap->db_type) {
1515 
1516 	case M_FLUSH:  /* Canonical flush handling */
1517 		if (*mp->b_rptr & FLUSHW) {
1518 			flushq(q, FLUSHDATA);
1519 		}
1520 		if (*mp->b_rptr & FLUSHR) {
1521 			flushq(RD(q), FLUSHDATA);
1522 		}
1523 		putnext(q, mp); /* pass it down the line. */
1524 		break;
1525 
1526 	case M_IOCTL:
1527 		usbwcm_ioctl(q, mp);
1528 		break;
1529 
1530 	case M_IOCDATA:
1531 		usbwcm_iocpy(q, mp);
1532 		break;
1533 
1534 	default:
1535 		putnext(q, mp); /* pass it down the line. */
1536 	}
1537 
1538 	return (0);
1539 }
1540 
1541 /*
1542  * usbwcm_rput() :
1543  *	Put procedure for input from driver end of stream (read queue).
1544  */
1545 static int
usbwcm_rput(queue_t * q,mblk_t * mp)1546 usbwcm_rput(queue_t *q, mblk_t *mp)
1547 {
1548 	usbwcm_state_t		*usbwcmp = q->q_ptr;
1549 	struct uwacom_softc	*sc = &usbwcmp->usbwcm_softc;
1550 	mblk_t			*mp0 = mp;
1551 	int			limit;
1552 
1553 	if (usbwcmp == 0) {
1554 		freemsg(mp);	/* nobody's listening */
1555 		return (0);
1556 	}
1557 
1558 	switch (mp->b_datap->db_type) {
1559 	case M_FLUSH:
1560 		if (*mp->b_rptr & FLUSHW)
1561 			flushq(WR(q), FLUSHDATA);
1562 
1563 		if (*mp->b_rptr & FLUSHR)
1564 			flushq(q, FLUSHDATA);
1565 
1566 		freemsg(mp);
1567 		return (0);
1568 
1569 	case M_BREAK:
1570 		/*
1571 		 * We don't have to handle this
1572 		 * because nothing is sent from the downstream
1573 		 */
1574 		freemsg(mp);
1575 		return (0);
1576 
1577 	case M_DATA:
1578 		if (!(usbwcmp->usbwcm_flags & USBWCM_OPEN)) {
1579 			freemsg(mp);	/* not ready to listen */
1580 
1581 			return (0);
1582 		}
1583 
1584 		/*
1585 		 * Make sure there are at least "limit" number of bytes.
1586 		 */
1587 		limit = uwacom_protocols[sc->sc_type->protocol].packet_size;
1588 		if (MBLKL(mp0) == limit) {	/* REMOVE */
1589 			do {
1590 				/* REMOVE */
1591 				usbwcm_input(usbwcmp, mp0);
1592 				mp0 = mp0->b_cont;
1593 			} while (mp0 != NULL);   /* next block, if any */
1594 		}
1595 
1596 		freemsg(mp);
1597 		break;
1598 
1599 	case M_CTL:
1600 		usbwcm_mctl(q, mp);
1601 		return (0);
1602 
1603 	case M_ERROR:
1604 		/* REMOVE */
1605 		usbwcmp->usbwcm_flags &= ~USBWCM_QWAIT;
1606 
1607 		freemsg(mp);
1608 		return (0);
1609 	default:
1610 		putnext(q, mp);
1611 		return (0);
1612 	}
1613 	return (0);
1614 }
1615 
1616 
1617 static struct module_info modinfo;
1618 
1619 /* STREAMS entry points */
1620 
1621 /* read side queue */
1622 static struct qinit rinit = {
1623 	.qi_putp = usbwcm_rput,
1624 	.qi_srvp = NULL,
1625 	.qi_qopen = usbwcm_open,
1626 	.qi_qclose = usbwcm_close,
1627 	.qi_qadmin = NULL,
1628 	.qi_minfo = &modinfo,
1629 	.qi_mstat = NULL
1630 };
1631 
1632 /* write side queue */
1633 static struct qinit winit = {
1634 	.qi_putp = usbwcm_wput,
1635 	.qi_srvp = NULL,
1636 	.qi_qopen = NULL,
1637 	.qi_qclose = NULL,
1638 	.qi_qadmin = NULL,
1639 	.qi_minfo = &modinfo,
1640 	.qi_mstat = NULL
1641 };
1642 
1643 /* STREAMS table */
1644 static struct streamtab strtab = {
1645 	&rinit,
1646 	&winit,
1647 	NULL,			/* not a MUX */
1648 	NULL			/* not a MUX */
1649 };
1650 
1651 /* Module linkage information */
1652 
1653 static struct fmodsw modsw = {
1654 	"usbwcm",
1655 	&strtab,
1656 	D_MP | D_MTPERMOD
1657 };
1658 
1659 
1660 static struct modlstrmod modlstr = {
1661 	&mod_strmodops,
1662 	"USB Wacom STRMOD",
1663 	&modsw
1664 };
1665 
1666 static struct modlinkage modlink = {
1667 	MODREV_1,
1668 	(void *)&modlstr,
1669 	NULL
1670 };
1671 
1672 static struct module_info modinfo = {
1673 	0x0ffff,		/* module id number */
1674 	"usbwcm",		/* module name */
1675 	0,			/* min packet size accepted */
1676 	INFPSZ,			/* max packet size accepted */
1677 	512,			/* hi-water mark */
1678 	128			/* lo-water mark */
1679 };
1680 
1681 
1682 /* Module entry points */
1683 
1684 int
_init(void)1685 _init(void)
1686 {
1687 	int rval = mod_install(&modlink);
1688 
1689 	if (rval == 0) {
1690 		usbwcm_log_handle = usb_alloc_log_hdl(NULL, "usbwcm",
1691 		    &usbwcm_errlevel, &usbwcm_errmask, NULL, 0);
1692 	}
1693 
1694 	return (rval);
1695 }
1696 
1697 int
_fini(void)1698 _fini(void)
1699 {
1700 	int rval = mod_remove(&modlink);
1701 
1702 	if (rval == 0) {
1703 		usb_free_log_hdl(usbwcm_log_handle);
1704 	}
1705 
1706 	return (rval);
1707 }
1708 
1709 int
_info(struct modinfo * modinfop)1710 _info(struct modinfo *modinfop)
1711 {
1712 
1713 	return (mod_info(&modlink, modinfop));
1714 }
1715