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