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