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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 1710 _info(struct modinfo *modinfop) 1711 { 1712 1713 return (mod_info(&modlink, modinfop)); 1714 } 1715