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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 1705 _info(struct modinfo *modinfop) 1706 { 1707 1708 return (mod_info(&modlink, modinfop)); 1709 }