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, NULL }
1664 };
1665 
1666 static struct module_info modinfo = {
1667         0x0ffff,                /* module id number */
1668         "usbwcm",               /* module name */
1669         0,                      /* min packet size accepted */
1670         INFPSZ,                 /* max packet size accepted */
1671         512,                    /* hi-water mark */
1672         128                     /* lo-water mark */
1673 };
1674 
1675 
1676 /* Module entry points */
1677 
1678 int
1679 _init(void)
1680 {
1681         int rval = mod_install(&modlink);
1682 
1683         if (rval == 0) {
1684                 usbwcm_log_handle = usb_alloc_log_hdl(NULL, "usbwcm",
1685                     &usbwcm_errlevel, &usbwcm_errmask, NULL, 0);
1686         }
1687 
1688         return (rval);
1689 }
1690 
1691 int
1692 _fini(void)
1693 {
1694         int rval = mod_remove(&modlink);
1695 
1696         if (rval == 0) {
1697                 usb_free_log_hdl(usbwcm_log_handle);
1698         }
1699 
1700         return (rval);
1701 }
1702 
1703 int
1704 _info(struct modinfo *modinfop)
1705 {
1706 
1707         return (mod_info(&modlink, modinfop));
1708 }