The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/common/io/usb/clients/usbinput/usbwcm/usbwcm.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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 }

Cache object: ad59d94f62c7aa82c140d60da0f06ef5


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.