Mercurial > illumos > illumos-gate
changeset 11489:29bcdf3d8d8c
PSARC/2009/621 usbwcm: Wacom USB Tablet STREAMS module
6901884 usbwcm: Wacom USB Tablet STREAMS module
author | Pengcheng Chen - Sun Microsystems - Beijing China <Pengcheng.Chen@Sun.COM> |
---|---|
date | Thu, 14 Jan 2010 17:07:01 +0800 |
parents | f39a595c0193 |
children | f88657db64df |
files | usr/src/pkgdefs/SUNWusb/prototype_i386 usr/src/pkgdefs/SUNWusb/prototype_sparc usr/src/pkgdefs/SUNWusbu/prototype_com usr/src/uts/common/Makefile.files usr/src/uts/common/Makefile.rules usr/src/uts/common/io/usb/clients/usbinput/usbwcm/usbwcm.c usr/src/uts/common/sys/Makefile usr/src/uts/common/sys/Makefile.syshdrs usr/src/uts/common/sys/usb/clients/usbinput/usbwcm/usbwcm.h usr/src/uts/intel/Makefile.intel.shared usr/src/uts/intel/usbwcm/Makefile usr/src/uts/sparc/Makefile.sparc.shared usr/src/uts/sparc/usbwcm/Makefile |
diffstat | 13 files changed, 2405 insertions(+), 12 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/pkgdefs/SUNWusb/prototype_i386 Wed Jan 13 19:48:54 2010 -0800 +++ b/usr/src/pkgdefs/SUNWusb/prototype_i386 Thu Jan 14 17:07:01 2010 +0800 @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Copyright 2010 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -68,6 +68,7 @@ f none kernel/misc/hwa1480_fw 0755 root sys f none kernel/strmod/usbkbm 0755 root sys f none kernel/strmod/usbms 0755 root sys +f none kernel/strmod/usbwcm 0755 root sys f none kernel/strmod/usb_ah 0755 root sys d none kernel/dacf/amd64 0755 root sys d none kernel/drv/amd64 0755 root sys @@ -94,4 +95,5 @@ d none kernel/strmod/amd64 0755 root sys f none kernel/strmod/amd64/usbkbm 0755 root sys f none kernel/strmod/amd64/usbms 0755 root sys +f none kernel/strmod/amd64/usbwcm 0755 root sys f none kernel/strmod/amd64/usb_ah 0755 root sys
--- a/usr/src/pkgdefs/SUNWusb/prototype_sparc Wed Jan 13 19:48:54 2010 -0800 +++ b/usr/src/pkgdefs/SUNWusb/prototype_sparc Thu Jan 14 17:07:01 2010 +0800 @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Copyright 2010 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -72,4 +72,5 @@ d none kernel/strmod/sparcv9 0755 root sys f none kernel/strmod/sparcv9/usbkbm 0755 root sys f none kernel/strmod/sparcv9/usbms 0755 root sys +f none kernel/strmod/sparcv9/usbwcm 0755 root sys f none kernel/strmod/sparcv9/usb_ah 0755 root sys
--- a/usr/src/pkgdefs/SUNWusbu/prototype_com Wed Jan 13 19:48:54 2010 -0800 +++ b/usr/src/pkgdefs/SUNWusbu/prototype_com Thu Jan 14 17:07:01 2010 +0800 @@ -20,7 +20,7 @@ # # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Copyright 2010 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -57,6 +57,8 @@ d none usr/include/sys/usb/clients/mass_storage 755 root bin d none usr/include/sys/usb/clients/printer 755 root bin d none usr/include/sys/usb/clients/usbcdc 755 root bin +d none usr/include/sys/usb/clients/usbinput 755 root bin +d none usr/include/sys/usb/clients/usbinput/usbwcm 755 root bin d none usr/include/sys/usb/clients/video 755 root bin d none usr/include/sys/usb/clients/video/usbvc 755 root bin d none usr/include/sys/uwb 755 root bin @@ -72,6 +74,7 @@ f none usr/include/sys/usb/clients/mass_storage/usb_cbi.h 644 root bin f none usr/include/sys/usb/clients/printer/usb_printer.h 644 root bin f none usr/include/sys/usb/clients/usbcdc/usb_cdc.h 644 root bin +f none usr/include/sys/usb/clients/usbinput/usbwcm/usbwcm.h 644 root bin f none usr/include/sys/usb/clients/video/usbvc/usbvc.h 644 root bin f none usr/include/sys/uwb/uwb.h 644 root bin f none usr/include/sys/uwb/uwbai.h 644 root bin
--- a/usr/src/uts/common/Makefile.files Wed Jan 13 19:48:54 2010 -0800 +++ b/usr/src/uts/common/Makefile.files Thu Jan 14 17:07:01 2010 +0800 @@ -728,6 +728,8 @@ USBKBM_OBJS += usbkbm.o +USBWCM_OBJS += usbwcm.o + BOFI_OBJS += bofi.o HID_OBJS += hid.o
--- a/usr/src/uts/common/Makefile.rules Wed Jan 13 19:48:54 2010 -0800 +++ b/usr/src/uts/common/Makefile.rules Thu Jan 14 17:07:01 2010 +0800 @@ -20,7 +20,7 @@ # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Copyright 2010 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # uts/common/Makefile.rules @@ -1142,6 +1142,10 @@ $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) +$(OBJS_DIR)/%.o: $(UTSBASE)/common/io/usb/clients/usbinput/usbwcm/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + $(OBJS_DIR)/%.o: $(UTSBASE)/common/io/usb/clients/ugen/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) @@ -2321,6 +2325,9 @@ $(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/usb/clients/usbms/%.c @($(LHEAD) $(LINT.c) $< $(LTAIL)) +$(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/usb/clients/usbinput/usbwcm/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + $(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/usb/clients/ugen/%.c @($(LHEAD) $(LINT.c) $< $(LTAIL))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/io/usb/clients/usbinput/usbwcm/usbwcm.c Thu Jan 14 17:07:01 2010 +0800 @@ -0,0 +1,1709 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Copyright (c) 2007, 2008 Bartosz Fabianowski <freebsd@chillt.de> + * All rights reserved. + * + * Financed by the "Irish Research Council for Science, Engineering and + * Technology: funded by the National Development Plan" + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Lennart Augustsson (lennart@augustsson.net) at + * Carlstedt Research & Technology. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/stropts.h> +#include <sys/strsun.h> +#include <sys/termios.h> +#include <sys/termio.h> +#include <sys/strtty.h> +#include <sys/systm.h> + +#include <sys/usb/usba/usbai_version.h> +#include <sys/usb/usba.h> +#include <sys/usb/usba/usbai_private.h> +#include <sys/usb/clients/hid/hid.h> +#include <sys/usb/clients/usbinput/usbwcm/usbwcm.h> + +/* debugging information */ +uint_t usbwcm_errmask = (uint_t)PRINT_MASK_ALL; +uint_t usbwcm_errlevel = USB_LOG_L2; +static usb_log_handle_t usbwcm_log_handle; + +static void +uwacom_event(usbwcm_state_t *usbwcmp, uint_t type, uint_t idx, int val) +{ + struct uwacom_softc *sc = &usbwcmp->usbwcm_softc; + mblk_t *mp; + + switch (type) { + case EVT_SYN: + if (sc->sc_sync) + return; + break; + + case EVT_BTN: + if (sc->sc_btn[idx] == val) + return; + + sc->sc_btn[idx] = val; + break; + + case EVT_ABS: + if (sc->sc_abs[idx].fuzz) { + int dist = abs(val - sc->sc_abs[idx].value); + + if (dist < sc->sc_abs[idx].fuzz >> 1) { + return; + } else if (dist < sc->sc_abs[idx].fuzz) { + val = (7 * sc->sc_abs[idx].value + val) >> 3; + } else if (dist < sc->sc_abs[idx].fuzz << 1) { + val = (sc->sc_abs[idx].value + val) >> 1; + } + } + if (sc->sc_abs[idx].value == val) { + return; + } + + sc->sc_abs[idx].value = val; + break; + + case EVT_REL: + if (!val) + return; + break; + + case EVT_MSC: + break; + + default: + return; + } + + if ((mp = allocb(sizeof (struct event_input), BPRI_HI)) != NULL) { + struct event_input *ev = (struct event_input *)mp->b_wptr; + + ev->type = (uint16_t)type; + ev->code = (uint16_t)idx; + ev->value = (int32_t)val; + uniqtime32(&ev->time); + + mp->b_wptr += sizeof (struct event_input); + putnext(usbwcmp->usbwcm_rq, mp); + } else { + return; + } + + sc->sc_sync = (type == EVT_SYN); +} + +static void +uwacom_pos_events_graphire(usbwcm_state_t *usbwcmp, int x, int y) +{ + uwacom_event(usbwcmp, EVT_ABS, ABS_X, x); + uwacom_event(usbwcmp, EVT_ABS, ABS_Y, y); +} + +static void +uwacom_pen_events_graphire(usbwcm_state_t *usbwcmp, int prs, int stl1, int stl2) +{ + uwacom_event(usbwcmp, EVT_ABS, ABS_PRESSURE, prs); + uwacom_event(usbwcmp, EVT_BTN, BTN_TIP, prs); + uwacom_event(usbwcmp, EVT_BTN, BTN_STYLUS_1, stl1); + uwacom_event(usbwcmp, EVT_BTN, BTN_STYLUS_2, stl2); +} + +static void +uwacom_mouse_events_graphire(usbwcm_state_t *usbwcmp, int left, int middle, + int right, int wheel, int distance) +{ + uwacom_event(usbwcmp, EVT_BTN, BTN_LEFT, left); + uwacom_event(usbwcmp, EVT_BTN, BTN_MIDDLE, middle); + uwacom_event(usbwcmp, EVT_BTN, BTN_RIGHT, right); + uwacom_event(usbwcmp, EVT_REL, REL_WHEEL, wheel); + uwacom_event(usbwcmp, EVT_ABS, ABS_DISTANCE, distance); +} + +static void +uwacom_tool_events_graphire(usbwcm_state_t *usbwcmp, int idx, int proximity) +{ + struct uwacom_softc *sc = &usbwcmp->usbwcm_softc; + + uwacom_event(usbwcmp, EVT_BTN, sc->sc_tool[idx], proximity); + uwacom_event(usbwcmp, EVT_ABS, ABS_MISC, sc->sc_tool_id[idx]); + if (sc->sc_serial[idx]) { + uwacom_event(usbwcmp, EVT_MSC, MSC_SERIAL, sc->sc_serial[idx]); + } + + uwacom_event(usbwcmp, EVT_SYN, SYN_REPORT, 0); +} + +static void +uwacom_pad_events_graphire4(usbwcm_state_t *usbwcmp, int b0, int b1, int b4, + int b5, int rel, int abs) +{ + uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_0, b0); + uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_1, b1); + uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_4, b4); + uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_5, b5); + uwacom_event(usbwcmp, EVT_REL, REL_WHEEL, rel); + uwacom_event(usbwcmp, EVT_ABS, ABS_WHEEL, abs); + uwacom_tool_events_graphire(usbwcmp, 1, b0 | b1 | b4 | b5 | rel | abs); +} + +static void +usbwcm_input_graphire(usbwcm_state_t *usbwcmp, mblk_t *mp) +{ + struct uwacom_softc *sc = &usbwcmp->usbwcm_softc; + uint8_t *packet = mp->b_rptr; + + if (PACKET_BITS(0, 0, 8) != 0x02) { + USB_DPRINTF_L1(PRINT_MASK_ALL, usbwcm_log_handle, + "unknown report type %02x received\n", + PACKET_BITS(0, 0, 8)); + return; + } + + /* Tool in proximity */ + if (PACKET_BIT(1, 7)) { + uwacom_pos_events_graphire(usbwcmp, + (PACKET_BITS(3, 0, 8) << 8) | PACKET_BITS(2, 0, 8), + (PACKET_BITS(5, 0, 8) << 8) | PACKET_BITS(4, 0, 8)); + + if (!PACKET_BIT(1, 6)) { + if (!PACKET_BIT(1, 5)) { + sc->sc_tool[0] = BTN_TOOL_PEN; + sc->sc_tool_id[0] = TOOL_ID_PEN; + } else { + sc->sc_tool[0] = BTN_TOOL_ERASER; + sc->sc_tool_id[0] = TOOL_ID_ERASER; + } + + uwacom_pen_events_graphire(usbwcmp, + (PACKET_BIT(7, 0) << 8) | PACKET_BITS(6, 0, 8), + PACKET_BIT(1, 1), PACKET_BIT(1, 2)); + } else { + int wheel, distance; + + if (sc->sc_type->protocol == GRAPHIRE) { + wheel = (PACKET_BIT(1, 5) ? + 0 : -(int8_t)PACKET_BITS(6, 0, 8)); + distance = PACKET_BITS(7, 0, 6); + } else { + wheel = (PACKET_BIT(7, 2) << 2) - + PACKET_BITS(7, 0, 2); + distance = PACKET_BITS(6, 0, 6); + } + + sc->sc_tool[0] = BTN_TOOL_MOUSE; + sc->sc_tool_id[0] = TOOL_ID_MOUSE; + + uwacom_mouse_events_graphire(usbwcmp, PACKET_BIT(1, 0), + PACKET_BIT(1, 2), PACKET_BIT(1, 1), wheel, + distance); + } + + uwacom_tool_events_graphire(usbwcmp, 0, 1); + + /* Tool leaving proximity */ + } else if (sc->sc_tool_id[0]) { + uwacom_pos_events_graphire(usbwcmp, 0, 0); + + if (sc->sc_tool[0] == BTN_TOOL_MOUSE) + uwacom_mouse_events_graphire(usbwcmp, 0, 0, 0, 0, 0); + else + uwacom_pen_events_graphire(usbwcmp, 0, 0, 0); + + sc->sc_tool_id[0] = 0; + uwacom_tool_events_graphire(usbwcmp, 0, 0); + } + + /* Finger on pad: Graphire4 */ + if ((sc->sc_type->protocol == GRAPHIRE4) && PACKET_BITS(7, 3, 5)) { + sc->sc_tool_id[1] = TOOL_ID_PAD; + uwacom_pad_events_graphire4(usbwcmp, PACKET_BIT(7, 6), 0, + PACKET_BIT(7, 7), 0, + PACKET_BITS(7, 3, 2) - (PACKET_BIT(7, 5) << 2), 0); + + /* Finger on pad: MyOffice */ + } else if ((sc->sc_type->protocol == MYOFFICE) && + (PACKET_BITS(7, 3, 4) || PACKET_BITS(8, 0, 8))) { + sc->sc_tool_id[1] = TOOL_ID_PAD; + uwacom_pad_events_graphire4(usbwcmp, PACKET_BIT(7, 3), + PACKET_BIT(7, 4), PACKET_BIT(7, 5), PACKET_BIT(7, 6), 0, + PACKET_BITS(8, 0, 7)); + + /* Finger leaving pad */ + } else if (sc->sc_tool_id[1]) { + sc->sc_tool_id[1] = 0; + uwacom_pad_events_graphire4(usbwcmp, 0, 0, 0, 0, 0, 0); + } +} + +static void +uwacom_pos_events_intuos(usbwcm_state_t *usbwcmp, int x, int y, int distance) +{ + uwacom_event(usbwcmp, EVT_ABS, ABS_X, x); + uwacom_event(usbwcmp, EVT_ABS, ABS_Y, y); + uwacom_event(usbwcmp, EVT_ABS, ABS_DISTANCE, distance); +} + +static void +uwacom_pen_events_intuos(usbwcm_state_t *usbwcmp, uint8_t *packet) +{ + struct uwacom_softc *sc = &usbwcmp->usbwcm_softc; + int press, tilt_x, tilt_y, stl1, stl2; + + switch (sc->sc_type->protocol) { + case INTUOS4S: + case INTUOS4L: + press = PACKET_BITS(7, 6, 10) << 1 | PACKET_BIT(1, 0); + break; + default: + press = PACKET_BITS(7, 6, 10); + break; + } + + tilt_x = PACKET_BITS(8, 7, 7); + tilt_y = PACKET_BITS(8, 0, 7); + stl1 = PACKET_BIT(1, 1); + stl2 = PACKET_BIT(1, 2); + + uwacom_event(usbwcmp, EVT_ABS, ABS_PRESSURE, press); + uwacom_event(usbwcmp, EVT_ABS, ABS_TILT_X, tilt_x); + uwacom_event(usbwcmp, EVT_ABS, ABS_TILT_Y, tilt_y); + uwacom_event(usbwcmp, EVT_BTN, BTN_TIP, press); + uwacom_event(usbwcmp, EVT_BTN, BTN_STYLUS_1, stl1); + uwacom_event(usbwcmp, EVT_BTN, BTN_STYLUS_2, stl2); +} + +static void +uwacom_mouse_events_intuos(usbwcm_state_t *usbwcmp, uint8_t *packet) +{ + struct uwacom_softc *sc = &usbwcmp->usbwcm_softc; + int left, middle, right, extra, side, wheel; + + switch (sc->sc_type->protocol) { + case INTUOS4S: + case INTUOS4L: + left = PACKET_BIT(6, 0); + middle = PACKET_BIT(6, 1); + right = PACKET_BIT(6, 2); + side = PACKET_BIT(6, 3); + extra = PACKET_BIT(6, 4); + wheel = PACKET_BIT(7, 7) - PACKET_BIT(7, 6); + break; + + default: + left = PACKET_BIT(8, 2); + middle = PACKET_BIT(8, 3); + right = PACKET_BIT(8, 4); + extra = PACKET_BIT(8, 5); + side = PACKET_BIT(8, 6); + wheel = PACKET_BIT(8, 0) - PACKET_BIT(8, 1); + break; + } + + uwacom_event(usbwcmp, EVT_BTN, BTN_LEFT, left); + uwacom_event(usbwcmp, EVT_BTN, BTN_MIDDLE, middle); + uwacom_event(usbwcmp, EVT_BTN, BTN_RIGHT, right); + uwacom_event(usbwcmp, EVT_BTN, BTN_EXTRA, extra); + uwacom_event(usbwcmp, EVT_BTN, BTN_SIDE, side); + uwacom_event(usbwcmp, EVT_REL, REL_WHEEL, wheel); +} + +static void +uwacom_tool_events_intuos(usbwcm_state_t *usbwcmp, int idx, int proximity) +{ + struct uwacom_softc *sc = &usbwcmp->usbwcm_softc; + + uwacom_event(usbwcmp, EVT_BTN, sc->sc_tool[idx], proximity); + uwacom_event(usbwcmp, EVT_ABS, ABS_MISC, sc->sc_tool_id[idx]); + uwacom_event(usbwcmp, EVT_MSC, MSC_SERIAL, sc->sc_serial[idx]); + uwacom_event(usbwcmp, EVT_SYN, SYN_REPORT, 0); +} + +static void +uwacom_pad_events_intuos(usbwcm_state_t *usbwcmp, uint8_t *packet) +{ + struct uwacom_softc *sc = &usbwcmp->usbwcm_softc; + int b0, b1, b2, b3, b4, b5, b6, b7; + int rx, ry, prox; + int b8, whl, rot; + + switch (sc->sc_type->protocol) { + case INTUOS4L: + b7 = PACKET_BIT(3, 6); + b8 = PACKET_BIT(3, 7); + + uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_7, b7); + uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_8, b8); + /*FALLTHRU*/ + case INTUOS4S: + b0 = PACKET_BIT(2, 0); + b1 = PACKET_BIT(3, 0); + b2 = PACKET_BIT(3, 1); + b3 = PACKET_BIT(3, 2); + b4 = PACKET_BIT(3, 3); + b5 = PACKET_BIT(3, 4); + b6 = PACKET_BIT(3, 5); + + uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_0, b0); + uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_1, b1); + uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_2, b2); + uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_3, b3); + uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_4, b4); + uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_5, b5); + uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_6, b6); + + whl = PACKET_BIT(1, 7); + if (whl) { + rot = PACKET_BITS(1, 0, 7); + uwacom_event(usbwcmp, EVT_ABS, ABS_WHEEL, rot); + } + + prox = b0 | b1 | b2 | b3 | b4 | b5 | b6 | b7 | b8 | whl; + uwacom_tool_events_intuos(usbwcmp, 1, prox); + + break; + + default: + b0 = PACKET_BIT(5, 0); + b1 = PACKET_BIT(5, 1); + b2 = PACKET_BIT(5, 2); + b3 = PACKET_BIT(5, 3); + b4 = PACKET_BIT(6, 0); + b5 = PACKET_BIT(6, 1); + b6 = PACKET_BIT(6, 2); + b7 = PACKET_BIT(6, 3); + rx = PACKET_BITS(2, 0, 13); + ry = PACKET_BITS(4, 0, 13); + + uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_0, b0); + uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_1, b1); + uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_2, b2); + uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_3, b3); + uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_4, b4); + uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_5, b5); + uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_6, b6); + uwacom_event(usbwcmp, EVT_BTN, BTN_MISC_7, b7); + uwacom_event(usbwcmp, EVT_ABS, ABS_RX, rx); + uwacom_event(usbwcmp, EVT_ABS, ABS_RY, ry); + + prox = b0 | b1 | b2 | b3 | b4 | b5 | b6 | b7 | rx | ry; + uwacom_tool_events_intuos(usbwcmp, 1, prox); + + break; + } +} + +static void +usbwcm_input_intuos(usbwcm_state_t *usbwcmp, mblk_t *mp) +{ + struct uwacom_softc *sc = &usbwcmp->usbwcm_softc; + uint8_t *packet = mp->b_rptr; + + switch (PACKET_BITS(0, 0, 8)) { + case 0x02: + switch (PACKET_BITS(1, 5, 2)) { + /* Tool entering proximity */ + case 0x2: + sc->sc_tool_id[0] = PACKET_BITS(3, 4, 12); + sc->sc_serial[0] = + (PACKET_BIT(1, 1) ? PACKET_BITS(7, 4, 32) : 0); + + switch (sc->sc_tool_id[0]) { + case 0x802: /* Intuos4 Grip Pen */ + case 0x804: /* Intuos4 Art Marker */ + case 0x823: /* Intuos3 Grip Pen */ + case 0x885: /* Intuos3 Art Marker */ + sc->sc_tool[0] = BTN_TOOL_PEN; + break; + case 0x80a: /* Intuos4 Grip Pen eraser */ + case 0x82b: /* Intuos3 Grip Pen eraser */ + sc->sc_tool[0] = BTN_TOOL_ERASER; + break; + case 0x017: /* Intuos3 2D mouse */ + case 0x806: /* Intuos4 2D mouse */ + sc->sc_tool[0] = BTN_TOOL_MOUSE; + break; + default: + USB_DPRINTF_L1(PRINT_MASK_ALL, + usbwcm_log_handle, + "unknown tool ID %03x seen\n", + sc->sc_tool_id[0]); + sc->sc_tool[0] = BTN_TOOL_PEN; + } + break; + + /* Tool leaving proximity */ + case 0x0: + uwacom_pos_events_intuos(usbwcmp, 0, 0, 0); + + if (sc->sc_tool[0] == BTN_TOOL_MOUSE) + uwacom_mouse_events_intuos(usbwcmp, packet); + else + uwacom_pen_events_intuos(usbwcmp, packet); + + sc->sc_tool_id[0] = 0; + uwacom_tool_events_intuos(usbwcmp, 0, 0); + break; + + /* Tool motion, outbound */ + case 0x1: + /* Outbound tracking is unreliable on the Cintiq */ + if (sc->sc_type->protocol == CINTIQ) + break; + + /* Tool motion */ + /*FALLTHRU*/ + case 0x3: + uwacom_pos_events_intuos(usbwcmp, + (PACKET_BITS(3, 0, 16) << 1) | PACKET_BIT(9, 1), + (PACKET_BITS(5, 0, 16) << 1) | PACKET_BIT(9, 0), + PACKET_BITS(9, 2, 6)); + + if (PACKET_BITS(1, 3, 2) == 0) { + uwacom_pen_events_intuos(usbwcmp, packet); + + } else if (PACKET_BITS(1, 1, 4) == 0x5) { + int angle = 450 - PACKET_BITS(7, 6, 10); + + if (PACKET_BIT(7, 5)) { + angle = (angle > 0 ? 900 : -900) - + angle; + } + + uwacom_event(usbwcmp, EVT_ABS, ABS_Z, angle); + break; + } else if (PACKET_BITS(1, 1, 4) == 0x8) { + uwacom_mouse_events_intuos(usbwcmp, packet); + } else { + USB_DPRINTF_L1(PRINT_MASK_ALL, + usbwcm_log_handle, + "unsupported motion packet type %x " + "received\n", PACKET_BITS(1, 1, 4)); + } + + uwacom_tool_events_intuos(usbwcmp, 0, 1); + break; + } + + break; + + case 0x0c: + uwacom_pad_events_intuos(usbwcmp, packet); + break; + + default: + USB_DPRINTF_L1(PRINT_MASK_ALL, usbwcm_log_handle, + "unknown report type %02x received\n", + PACKET_BITS(0, 0, 8)); + } +} + +static void +uwacom_init_abs(usbwcm_state_t *usbwcmp, int axis, int32_t min, int32_t max, + int32_t fuzz, int32_t flat) +{ + struct uwacom_softc *sc = &usbwcmp->usbwcm_softc; + + sc->sc_abs[axis].min = min; + sc->sc_abs[axis].max = max; + sc->sc_abs[axis].fuzz = fuzz; + sc->sc_abs[axis].flat = flat; +} + +static void +uwacom_init_graphire4(usbwcm_state_t *usbwcmp) +{ + struct uwacom_softc *sc = &usbwcmp->usbwcm_softc; + + BM_SET_BIT(sc->sc_bm[0], EVT_MSC); + BM_SET_BIT(sc->sc_bm[1], BTN_MISC_0); + BM_SET_BIT(sc->sc_bm[1], BTN_MISC_4); + BM_SET_BIT(sc->sc_bm[1], BTN_TOOL_PAD); + BM_SET_BIT(sc->sc_bm[4], MSC_SERIAL); + + sc->sc_tool[1] = BTN_TOOL_PAD; + sc->sc_serial[1] = SERIAL_PAD_GRAPHIRE4; +} + +static void +uwacom_init_myoffice(usbwcm_state_t *usbwcmp) +{ + struct uwacom_softc *sc = &usbwcmp->usbwcm_softc; + + BM_SET_BIT(sc->sc_bm[1], BTN_MISC_1); + BM_SET_BIT(sc->sc_bm[1], BTN_MISC_5); + BM_SET_BIT(sc->sc_bm[3], ABS_WHEEL); + + uwacom_init_abs(usbwcmp, ABS_WHEEL, 0, 71, 0, 0); +} + +static void +uwacom_init_intuos(usbwcm_state_t *usbwcmp) +{ + struct uwacom_softc *sc = &usbwcmp->usbwcm_softc; + + BM_SET_BIT(sc->sc_bm[0], EVT_MSC); + + BM_SET_BIT(sc->sc_bm[1], BTN_MISC_0); + BM_SET_BIT(sc->sc_bm[1], BTN_MISC_1); + BM_SET_BIT(sc->sc_bm[1], BTN_MISC_2); + BM_SET_BIT(sc->sc_bm[1], BTN_MISC_3); + BM_SET_BIT(sc->sc_bm[1], BTN_SIDE); + BM_SET_BIT(sc->sc_bm[1], BTN_EXTRA); + BM_SET_BIT(sc->sc_bm[1], BTN_TOOL_PAD); + + BM_SET_BIT(sc->sc_bm[3], ABS_TILT_X); + BM_SET_BIT(sc->sc_bm[3], ABS_TILT_Y); + + BM_SET_BIT(sc->sc_bm[4], MSC_SERIAL); + + sc->sc_tool[1] = BTN_TOOL_PAD; + sc->sc_tool_id[1] = TOOL_ID_PAD; + sc->sc_serial[1] = SERIAL_PAD_INTUOS; +} + +static void +uwacom_init_intuos3(usbwcm_state_t *usbwcmp) +{ + struct uwacom_softc *sc = &usbwcmp->usbwcm_softc; + + BM_SET_BIT(sc->sc_bm[3], ABS_Z); + BM_SET_BIT(sc->sc_bm[3], ABS_RX); + + uwacom_init_abs(usbwcmp, ABS_Z, -900, 899, 0, 0); + uwacom_init_abs(usbwcmp, ABS_RX, 0, 4096, 0, 0); +} + +static void +uwacom_init_intuos3_large(usbwcm_state_t *usbwcmp) +{ + struct uwacom_softc *sc = &usbwcmp->usbwcm_softc; + + BM_SET_BIT(sc->sc_bm[1], BTN_MISC_4); + BM_SET_BIT(sc->sc_bm[1], BTN_MISC_5); + BM_SET_BIT(sc->sc_bm[1], BTN_MISC_6); + BM_SET_BIT(sc->sc_bm[1], BTN_MISC_7); + + BM_SET_BIT(sc->sc_bm[3], ABS_RY); + + uwacom_init_abs(usbwcmp, ABS_RY, 0, 4096, 0, 0); +} + +static void +uwacom_init_intuos4(usbwcm_state_t *usbwcmp) +{ + struct uwacom_softc *sc = &usbwcmp->usbwcm_softc; + + BM_SET_BIT(sc->sc_bm[1], BTN_MISC_4); + BM_SET_BIT(sc->sc_bm[1], BTN_MISC_5); + BM_SET_BIT(sc->sc_bm[1], BTN_MISC_6); + + BM_SET_BIT(sc->sc_bm[3], ABS_Z); + + uwacom_init_abs(usbwcmp, ABS_Z, -900, 899, 0, 0); +} +static void +uwacom_init_intuos4_large(usbwcm_state_t *usbwcmp) +{ + struct uwacom_softc *sc = &usbwcmp->usbwcm_softc; + + BM_SET_BIT(sc->sc_bm[1], BTN_MISC_7); + BM_SET_BIT(sc->sc_bm[1], BTN_MISC_8); +} + +static int +uwacom_init(usbwcm_state_t *usbwcmp) +{ + struct uwacom_softc *sc = &usbwcmp->usbwcm_softc; + + sc->sc_id.bus = ID_BUS_USB; + sc->sc_id.vendor = usbwcmp->usbwcm_devid.VendorId; + sc->sc_id.product = usbwcmp->usbwcm_devid.ProductId; + + sc->sc_id.version = 0; + + for (int i = 0; i < EVT_USED; ++i) + sc->sc_bm[i] = kmem_zalloc(bm_size[i], KM_SLEEP); + + sc->sc_btn = kmem_zalloc(BTN_USED * sizeof (int), KM_SLEEP); + sc->sc_abs = kmem_zalloc(ABS_USED * sizeof (struct event_abs_axis), + KM_SLEEP); + + BM_SET_BIT(sc->sc_bm[0], EVT_SYN); + BM_SET_BIT(sc->sc_bm[0], EVT_BTN); + BM_SET_BIT(sc->sc_bm[0], EVT_REL); + BM_SET_BIT(sc->sc_bm[0], EVT_ABS); + + BM_SET_BIT(sc->sc_bm[1], BTN_LEFT); + BM_SET_BIT(sc->sc_bm[1], BTN_RIGHT); + BM_SET_BIT(sc->sc_bm[1], BTN_MIDDLE); + BM_SET_BIT(sc->sc_bm[1], BTN_TOOL_PEN); + BM_SET_BIT(sc->sc_bm[1], BTN_TOOL_ERASER); + BM_SET_BIT(sc->sc_bm[1], BTN_TOOL_MOUSE); + BM_SET_BIT(sc->sc_bm[1], BTN_TIP); + BM_SET_BIT(sc->sc_bm[1], BTN_STYLUS_1); + BM_SET_BIT(sc->sc_bm[1], BTN_STYLUS_2); + + BM_SET_BIT(sc->sc_bm[2], REL_WHEEL); + + BM_SET_BIT(sc->sc_bm[3], ABS_X); + BM_SET_BIT(sc->sc_bm[3], ABS_Y); + BM_SET_BIT(sc->sc_bm[3], ABS_PRESSURE); + BM_SET_BIT(sc->sc_bm[3], ABS_DISTANCE); + BM_SET_BIT(sc->sc_bm[3], ABS_MISC); + + uwacom_init_abs(usbwcmp, ABS_X, 0, sc->sc_type->x_max, 4, 0); + uwacom_init_abs(usbwcmp, ABS_Y, 0, sc->sc_type->y_max, 4, 0); + uwacom_init_abs(usbwcmp, ABS_PRESSURE, 0, sc->sc_type->pressure_max, + 0, 0); + uwacom_init_abs(usbwcmp, ABS_DISTANCE, 0, + uwacom_protocols[sc->sc_type->protocol].distance_max, 0, 0); + + switch (sc->sc_type->protocol) { + case CINTIQ: + case INTUOS3L: + uwacom_init_intuos3_large(usbwcmp); + /*FALLTHRU*/ + case INTUOS3S: + uwacom_init_intuos3(usbwcmp); + uwacom_init_intuos(usbwcmp); + break; + + case INTUOS4L: + uwacom_init_intuos4_large(usbwcmp); + /*FALLTHRU*/ + case INTUOS4S: + uwacom_init_intuos4(usbwcmp); + uwacom_init_intuos(usbwcmp); + break; + case MYOFFICE: + uwacom_init_myoffice(usbwcmp); + /*FALLTHRU*/ + case GRAPHIRE4: + uwacom_init_graphire4(usbwcmp); + /*FALLTHRU*/ + case GRAPHIRE: + break; + } + + return (0); +} + +/* + * usbwcm_match() : + * Match device with it's parameters. + */ +static const struct uwacom_type * +usbwcm_match(uint16_t vid, uint16_t pid) +{ + const struct uwacom_type *dev; + + dev = uwacom_devs; + while (dev->devno.vid != 0 && dev->devno.pid != 0) { + if (dev->devno.vid == vid && dev->devno.pid == pid) { + return (dev); + } + dev++; + } + + return (NULL); +} + +/* + * usbwcm_probe() : + * Check the device type and protocol. + */ +static int +usbwcm_probe(usbwcm_state_t *usbwcmp) +{ + queue_t *q = usbwcmp->usbwcm_rq; + mblk_t *mctl_ptr; + struct iocblk mctlmsg; + hid_req_t *featr; + + /* check device IDs */ + mctlmsg.ioc_cmd = HID_GET_VID_PID; + mctlmsg.ioc_count = 0; + + mctl_ptr = usba_mk_mctl(mctlmsg, NULL, 0); + if (mctl_ptr == NULL) { + return (ENOMEM); + } + + putnext(usbwcmp->usbwcm_wq, mctl_ptr); + usbwcmp->usbwcm_flags |= USBWCM_QWAIT; + + while (usbwcmp->usbwcm_flags & USBWCM_QWAIT) { + if (qwait_sig(q) == 0) { + usbwcmp->usbwcm_flags = 0; + return (EINTR); + } + } + + usbwcmp->usbwcm_softc.sc_type = + usbwcm_match(usbwcmp->usbwcm_devid.VendorId, + usbwcmp->usbwcm_devid.ProductId); + if (!usbwcmp->usbwcm_softc.sc_type) { + USB_DPRINTF_L1(PRINT_MASK_ALL, usbwcm_log_handle, + "unsupported tablet model\n"); + return (ENXIO); + } + + if (uwacom_init(usbwcmp) != 0) { + return (ENXIO); + } + + /* set feature: tablet mode */ + featr = kmem_zalloc(sizeof (hid_req_t), KM_SLEEP); + featr->hid_req_version_no = HID_VERSION_V_0; + featr->hid_req_wValue = REPORT_TYPE_FEATURE | 2; + featr->hid_req_wLength = sizeof (uint8_t) * 2; + featr->hid_req_data[0] = 2; + featr->hid_req_data[1] = 2; + + mctlmsg.ioc_cmd = HID_SET_REPORT; + mctlmsg.ioc_count = sizeof (featr); + mctl_ptr = usba_mk_mctl(mctlmsg, featr, sizeof (hid_req_t)); + if (mctl_ptr != NULL) { + putnext(usbwcmp->usbwcm_wq, mctl_ptr); + + /* + * Waiting for response of HID_SET_REPORT + * mctl for setting the feature. + */ + usbwcmp->usbwcm_flags |= USBWCM_QWAIT; + while (usbwcmp->usbwcm_flags & USBWCM_QWAIT) { + qwait(q); + } + } else { + USB_DPRINTF_L1(PRINT_MASK_ALL, usbwcm_log_handle, + "enable tablet mode failed\n"); + } + + kmem_free(featr, sizeof (hid_req_t)); + + return (0); +} + +/* + * usbwcm_copyreq() : + * helper function for usbwcm ioctls + */ +static int +usbwcm_copyreq(mblk_t *mp, uint_t pvtsize, uint_t state, uint_t reqsize, + uint_t contsize, uint_t copytype) +{ + usbwcm_copyin_t *copystat; + mblk_t *iocmp, *contmp; + struct copyreq *cq; + struct copyresp *cr; + + if ((pvtsize == 0) && (state != 0)) { + cr = (struct copyresp *)mp->b_rptr; + iocmp = cr->cp_private; + } + + cq = (struct copyreq *)mp->b_rptr; + if (mp->b_cont == NULL) { + + return (EINVAL); + } + + cq->cq_addr = *((caddr_t *)mp->b_cont->b_rptr); + cq->cq_size = reqsize; + cq->cq_flag = 0; + + if (pvtsize) { + iocmp = (mblk_t *)allocb(pvtsize, BPRI_MED); + if (iocmp == NULL) { + + return (EAGAIN); + } + cq->cq_private = iocmp; + iocmp = cq->cq_private; + } else { + /* + * Here we need to set cq_private even if there's + * no private data, otherwise its value will be + * TRANSPARENT (-1) on 64bit systems because it + * overlaps iocp->ioc_count. If user address (cq_addr) + * is invalid, it would cause panic later in + * usbwcm_copyin: + * freemsg((mblk_t *)copyresp->cp_private); + */ + cq->cq_private = NULL; + } + + if (state) { + copystat = (usbwcm_copyin_t *)iocmp->b_rptr; + copystat->state = state; + if (pvtsize) { /* M_COPYIN */ + copystat->addr = cq->cq_addr; + } else { + cq->cq_addr = copystat->addr; + cq->cq_private = iocmp; + } + iocmp->b_wptr = iocmp->b_rptr + sizeof (usbwcm_copyin_t); + } + + if (contsize) { + contmp = (mblk_t *)allocb(contsize, BPRI_MED); + if (contmp == NULL) { + + return (EAGAIN); + } + if (mp->b_cont) { + freemsg(mp->b_cont); + mp->b_cont = contmp; + } + } + + mp->b_datap->db_type = (unsigned char)copytype; + mp->b_wptr = mp->b_rptr + sizeof (struct copyreq); + + return (0); +} + +static void +usbwcm_miocack(queue_t *q, mblk_t *mp, int rval) +{ + struct iocblk *iocbp = (struct iocblk *)mp->b_rptr; + + mp->b_datap->db_type = M_IOCACK; + mp->b_wptr = mp->b_rptr + sizeof (struct iocblk); + + iocbp->ioc_error = 0; + iocbp->ioc_count = 0; + iocbp->ioc_rval = rval; + + if (mp->b_cont != NULL) { + freemsg(mp->b_cont); + mp->b_cont = NULL; + } + + qreply(q, mp); +} + +/* + * usbwcm_iocpy() : + * M_IOCDATA processing for IOCTL's + */ +static void +usbwcm_iocpy(queue_t *q, mblk_t *mp) +{ + usbwcm_state_t *usbwcmp = (usbwcm_state_t *)q->q_ptr; + struct uwacom_softc *sc = &usbwcmp->usbwcm_softc; + struct copyresp *copyresp; + usbwcm_copyin_t *copystat; + mblk_t *datap, *ioctmp; + struct iocblk *iocbp; + int err = 0; + + copyresp = (struct copyresp *)mp->b_rptr; + iocbp = (struct iocblk *)mp->b_rptr; + if (copyresp->cp_rval) { + err = EAGAIN; + + goto out; + } + + switch (copyresp->cp_cmd) { + default: { + int num = copyresp->cp_cmd & 0xff; + int len = IOCPARM_MASK & (copyresp->cp_cmd >> 16); + + if (((copyresp->cp_cmd >> 8) & 0xFF) != 'E') { + putnext(q, mp); /* pass it down the line */ + return; + + } else if ((copyresp->cp_cmd & IOC_INOUT) != IOC_OUT) { + err = EINVAL; + break; + } + + switch (num) { + case EUWACOMGETVERSION: + ioctmp = copyresp->cp_private; + copystat = (usbwcm_copyin_t *)ioctmp->b_rptr; + if (copystat->state == USBWCM_GETSTRUCT) { + if (mp->b_cont == NULL) { + err = EINVAL; + + break; + } + datap = (mblk_t *)mp->b_cont; + + *(int *)datap->b_rptr = 0x00010000; + + if (err = usbwcm_copyreq(mp, 0, + USBWCM_GETRESULT, sizeof (int), 0, + M_COPYOUT)) { + + goto out; + } + } else if (copystat->state == USBWCM_GETRESULT) { + freemsg(ioctmp); + usbwcm_miocack(q, mp, 0); + return; + } + break; + + case EUWACOMGETID: + ioctmp = copyresp->cp_private; + copystat = (usbwcm_copyin_t *)ioctmp->b_rptr; + if (copystat->state == USBWCM_GETSTRUCT) { + if (mp->b_cont == NULL) { + err = EINVAL; + + break; + } + datap = (mblk_t *)mp->b_cont; + + bcopy(&sc->sc_id, datap->b_rptr, + sizeof (struct event_dev_id)); + + if (err = usbwcm_copyreq(mp, 0, + USBWCM_GETRESULT, + sizeof (struct event_dev_id), 0, + M_COPYOUT)) { + + goto out; + } + } else if (copystat->state == USBWCM_GETRESULT) { + freemsg(ioctmp); + usbwcm_miocack(q, mp, 0); + return; + } + break; + + default: + if (num >= EUWACOMGETBM && + num < EUWACOMGETBM + EVT_USED) { + int idx = num - EUWACOMGETBM; + size_t length = min(bm_size[idx], len); + + ioctmp = copyresp->cp_private; + copystat = (usbwcm_copyin_t *)ioctmp->b_rptr; + if (copystat->state == USBWCM_GETSTRUCT) { + if (mp->b_cont == NULL) { + err = EINVAL; + + break; + } + datap = (mblk_t *)mp->b_cont; + + bcopy(sc->sc_bm[idx], datap->b_rptr, + length); + + if (err = usbwcm_copyreq(mp, 0, + USBWCM_GETRESULT, length, 0, + M_COPYOUT)) { + + goto out; + } + + } else if (copystat->state == + USBWCM_GETRESULT) { + freemsg(ioctmp); + usbwcm_miocack(q, mp, length); + return; + } + break; + + } else if (num >= EUWACOMGETABS && + num < EUWACOMGETABS + ABS_USED) { + int idx = num - EUWACOMGETABS; + + ioctmp = copyresp->cp_private; + copystat = (usbwcm_copyin_t *)ioctmp->b_rptr; + if (copystat->state == USBWCM_GETSTRUCT) { + if (mp->b_cont == NULL) { + err = EINVAL; + + break; + } + datap = (mblk_t *)mp->b_cont; + + bcopy(&sc->sc_abs[idx], datap->b_rptr, + sizeof (struct event_abs_axis)); + + if (err = usbwcm_copyreq(mp, 0, + USBWCM_GETRESULT, + sizeof (struct event_abs_axis), 0, + M_COPYOUT)) { + + goto out; + } + + } else if (copystat->state == + USBWCM_GETRESULT) { + freemsg(ioctmp); + usbwcm_miocack(q, mp, 0); + return; + } + break; + + } else { + err = EINVAL; + break; + } + } + } + } + +out: + if (err) { + mp->b_datap->db_type = M_IOCNAK; + if (mp->b_cont) { + freemsg(mp->b_cont); + mp->b_cont = (mblk_t *)NULL; + } + if (copyresp->cp_private) { + freemsg((mblk_t *)copyresp->cp_private); + copyresp->cp_private = (mblk_t *)NULL; + } + iocbp->ioc_count = 0; + iocbp->ioc_error = err; + } + + qreply(q, mp); +} + +/* + * usbwcm_ioctl() : + * Process ioctls we recognize and own. Otherwise, NAK. + */ +static void +usbwcm_ioctl(queue_t *q, mblk_t *mp) +{ + usbwcm_state_t *usbwcmp = (usbwcm_state_t *)q->q_ptr; + struct uwacom_softc *sc; + mblk_t *datap; + struct iocblk *iocp; + int err = 0; + + if (usbwcmp == NULL) { + miocnak(q, mp, 0, EINVAL); + return; + } + + sc = &usbwcmp->usbwcm_softc; + iocp = (struct iocblk *)mp->b_rptr; + + switch (iocp->ioc_cmd) { + default: { + int num = iocp->ioc_cmd & 0xff; + int len = IOCPARM_MASK & (iocp->ioc_cmd >> 16); + + if (((iocp->ioc_cmd >> 8) & 0xFF) != 'E') { + putnext(q, mp); /* pass it down the line */ + return; + + } else if ((iocp->ioc_cmd & IOC_INOUT) != IOC_OUT) { + err = EINVAL; + break; + } + + switch (num) { + case EUWACOMGETVERSION: + if (iocp->ioc_count == TRANSPARENT) { + if (err = usbwcm_copyreq(mp, + sizeof (usbwcm_copyin_t), USBWCM_GETSTRUCT, + sizeof (int), 0, M_COPYIN)) { + break; + } + freemsg(mp->b_cont); + mp->b_cont = (mblk_t *)NULL; + + qreply(q, mp); + return; + } + + if (mp->b_cont == NULL || + iocp->ioc_count != sizeof (int)) { + err = EINVAL; + break; + } + datap = mp->b_cont; + + *(int *)datap->b_rptr = 0x00010000; + + break; + + case EUWACOMGETID: + if (iocp->ioc_count == TRANSPARENT) { + if (err = usbwcm_copyreq(mp, + sizeof (usbwcm_copyin_t), USBWCM_GETSTRUCT, + sizeof (struct event_dev_id), 0, + M_COPYIN)) { + break; + } + freemsg(mp->b_cont); + mp->b_cont = (mblk_t *)NULL; + + qreply(q, mp); + return; + } + + if (mp->b_cont == NULL || + iocp->ioc_count != sizeof (struct event_dev_id)) { + err = EINVAL; + break; + } + datap = mp->b_cont; + + bcopy(&sc->sc_id, datap->b_rptr, + sizeof (struct event_dev_id)); + + break; + + default: + if (num >= EUWACOMGETBM && + num < EUWACOMGETBM + EVT_USED) { + int idx = num - EUWACOMGETBM; + size_t length = min(bm_size[idx], len); + + if (iocp->ioc_count == TRANSPARENT) { + if (err = usbwcm_copyreq(mp, + sizeof (usbwcm_copyin_t), + USBWCM_GETSTRUCT, length, 0, + M_COPYIN)) { + break; + } + freemsg(mp->b_cont); + mp->b_cont = (mblk_t *)NULL; + + qreply(q, mp); + return; + } + + if (mp->b_cont == NULL || + iocp->ioc_count != length) { + err = EINVAL; + break; + } + datap = mp->b_cont; + + bcopy(sc->sc_bm[idx], datap->b_rptr, length); + + break; + + } else if (num >= EUWACOMGETABS && + num < EUWACOMGETABS + ABS_USED) { + int idx = num - EUWACOMGETABS; + + if (iocp->ioc_count == TRANSPARENT) { + if (err = usbwcm_copyreq(mp, + sizeof (usbwcm_copyin_t), + USBWCM_GETSTRUCT, + sizeof (struct event_abs_axis), 0, + M_COPYIN)) { + break; + } + freemsg(mp->b_cont); + mp->b_cont = (mblk_t *)NULL; + + qreply(q, mp); + return; + } + + if (mp->b_cont == NULL || + iocp->ioc_count != + sizeof (struct event_abs_axis)) { + err = EINVAL; + break; + } + datap = mp->b_cont; + + bcopy(&sc->sc_abs[idx], datap->b_rptr, + sizeof (struct event_abs_axis)); + + break; + + } else { + err = EINVAL; + break; + } + } + } + } + + if (err != 0) + miocnak(q, mp, 0, err); + else { + iocp->ioc_rval = 0; + iocp->ioc_error = 0; + mp->b_datap->db_type = M_IOCACK; + qreply(q, mp); + /* REMOVE */ + } + + return; + +} + +/* + * usbwcm_input() : + * + * Wacom input routine; process data received from a device and + * assemble into a input event for the window system. + * + * Watch out for overflow! + */ +static void +usbwcm_input(usbwcm_state_t *usbwcmp, mblk_t *mp) +{ + struct uwacom_softc *sc = &usbwcmp->usbwcm_softc; + + switch (sc->sc_type->protocol) { + case GRAPHIRE: + case GRAPHIRE4: + case MYOFFICE: + usbwcm_input_graphire(usbwcmp, mp); + break; + + case INTUOS3S: + case INTUOS3L: + case INTUOS4S: + case INTUOS4L: + case CINTIQ: + usbwcm_input_intuos(usbwcmp, mp); + break; + } +} + +/* + * usbwcm_flush() : + * Resets the soft state to default values + * and sends M_FLUSH above. + */ +static void +usbwcm_flush(usbwcm_state_t *usbwcmp) +{ + queue_t *q; + + if ((q = usbwcmp->usbwcm_rq) != NULL && q->q_next != NULL) { + (void) putnextctl1(q, M_FLUSH, FLUSHR); + } +} + +/* + * usbwcm_mctl() : + * Handle M_CTL messages from hid. If + * we don't understand the command, free message. + */ +static void +usbwcm_mctl(queue_t *q, mblk_t *mp) +{ + usbwcm_state_t *usbwcmp = (usbwcm_state_t *)q->q_ptr; + struct iocblk *iocp; + caddr_t data = NULL; + struct iocblk mctlmsg; + mblk_t *mctl_ptr; + hid_req_t *featr; + + iocp = (struct iocblk *)mp->b_rptr; + if (mp->b_cont != NULL) + data = (caddr_t)mp->b_cont->b_rptr; + + switch (iocp->ioc_cmd) { + case HID_GET_VID_PID: + if ((data != NULL) && + (iocp->ioc_count == sizeof (hid_vid_pid_t)) && + (MBLKL(mp->b_cont) == iocp->ioc_count)) { + bcopy(data, &usbwcmp->usbwcm_devid, iocp->ioc_count); + } + + freemsg(mp); + usbwcmp->usbwcm_flags &= ~USBWCM_QWAIT; + break; + + case HID_CONNECT_EVENT: + /* set feature: tablet mode */ + featr = kmem_zalloc(sizeof (hid_req_t), KM_SLEEP); + featr->hid_req_version_no = HID_VERSION_V_0; + featr->hid_req_wValue = REPORT_TYPE_FEATURE | 2; + featr->hid_req_wLength = sizeof (uint8_t) * 2; + featr->hid_req_data[0] = 2; + featr->hid_req_data[1] = 2; + + mctlmsg.ioc_cmd = HID_SET_REPORT; + mctlmsg.ioc_count = sizeof (featr); + mctl_ptr = usba_mk_mctl(mctlmsg, featr, sizeof (hid_req_t)); + if (mctl_ptr != NULL) { + putnext(usbwcmp->usbwcm_wq, mctl_ptr); + } else { + USB_DPRINTF_L1(PRINT_MASK_ALL, usbwcm_log_handle, + "enable tablet mode failed\n"); + } + + kmem_free(featr, sizeof (hid_req_t)); + freemsg(mp); + break; + + case HID_SET_REPORT: + /* FALLTHRU */ + + case HID_SET_PROTOCOL: + usbwcmp->usbwcm_flags &= ~USBWCM_QWAIT; + /* FALLTHRU */ + + default: + freemsg(mp); + } +} + +/* + * usbwcm_open() : + * open() entry point for the USB wacom module. + */ +/*ARGSUSED*/ +static int +usbwcm_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp) +{ + usbwcm_state_t *usbwcmp; + + /* Clone opens are not allowed */ + if (sflag != MODOPEN) + return (EINVAL); + + /* If the module is already open, just return */ + if (q->q_ptr) { + return (0); + } + + /* allocate usbwcm state structure */ + usbwcmp = kmem_zalloc(sizeof (usbwcm_state_t), KM_SLEEP); + + q->q_ptr = usbwcmp; + WR(q)->q_ptr = usbwcmp; + + usbwcmp->usbwcm_rq = q; + usbwcmp->usbwcm_wq = WR(q); + + qprocson(q); + + if (usbwcm_probe(usbwcmp) != 0) { + + qprocsoff(q); + kmem_free(usbwcmp, sizeof (usbwcm_state_t)); + + return (EINVAL); + } + + usbwcm_flush(usbwcmp); + + usbwcmp->usbwcm_flags |= USBWCM_OPEN; + return (0); +} + + +/* + * usbwcm_close() : + * close() entry point for the USB wacom module. + */ +/*ARGSUSED*/ +static int +usbwcm_close(queue_t *q, int flag, cred_t *credp) +{ + usbwcm_state_t *usbwcmp = q->q_ptr; + struct uwacom_softc *sc = &usbwcmp->usbwcm_softc; + + qprocsoff(q); + + if (usbwcmp->usbwcm_bufcall) { + qunbufcall(q, (bufcall_id_t)(long)usbwcmp->usbwcm_bufcall); + usbwcmp->usbwcm_bufcall = 0; + } + + if (usbwcmp->usbwcm_mioctl != NULL) { + /* + * We were holding an "ioctl" response pending the + * availability of an "mblk" to hold data to be passed up; + * another "ioctl" came through, which means that "ioctl" + * must have timed out or been aborted. + */ + freemsg(usbwcmp->usbwcm_mioctl); + usbwcmp->usbwcm_mioctl = NULL; + } + + for (int i = 0; i < EVT_USED; i++) + kmem_free(sc->sc_bm[i], bm_size[i]); + + kmem_free(sc->sc_btn, BTN_USED * sizeof (int)); + kmem_free(sc->sc_abs, ABS_USED * sizeof (struct event_abs_axis)); + kmem_free(usbwcmp, sizeof (usbwcm_state_t)); + + q->q_ptr = WR(q)->q_ptr = NULL; + return (0); +} + +/* + * usbwcm_wput() : + * wput() routine for the wacom module. + * Module below : hid, module above : consms + */ +static int +usbwcm_wput(queue_t *q, mblk_t *mp) +{ + switch (mp->b_datap->db_type) { + + case M_FLUSH: /* Canonical flush handling */ + if (*mp->b_rptr & FLUSHW) { + flushq(q, FLUSHDATA); + } + if (*mp->b_rptr & FLUSHR) { + flushq(RD(q), FLUSHDATA); + } + putnext(q, mp); /* pass it down the line. */ + break; + + case M_IOCTL: + usbwcm_ioctl(q, mp); + break; + + case M_IOCDATA: + usbwcm_iocpy(q, mp); + break; + + default: + putnext(q, mp); /* pass it down the line. */ + } + + return (0); +} + +/* + * usbwcm_rput() : + * Put procedure for input from driver end of stream (read queue). + */ +static void +usbwcm_rput(queue_t *q, mblk_t *mp) +{ + usbwcm_state_t *usbwcmp = q->q_ptr; + struct uwacom_softc *sc = &usbwcmp->usbwcm_softc; + mblk_t *mp0 = mp; + int limit; + + if (usbwcmp == 0) { + freemsg(mp); /* nobody's listening */ + return; + } + + switch (mp->b_datap->db_type) { + case M_FLUSH: + if (*mp->b_rptr & FLUSHW) + flushq(WR(q), FLUSHDATA); + + if (*mp->b_rptr & FLUSHR) + flushq(q, FLUSHDATA); + + freemsg(mp); + return; + + case M_BREAK: + /* + * We don't have to handle this + * because nothing is sent from the downstream + */ + freemsg(mp); + return; + + case M_DATA: + if (!(usbwcmp->usbwcm_flags & USBWCM_OPEN)) { + freemsg(mp); /* not ready to listen */ + + return; + } + + /* + * Make sure there are at least "limit" number of bytes. + */ + limit = uwacom_protocols[sc->sc_type->protocol].packet_size; + if (MBLKL(mp0) == limit) { /* REMOVE */ + do { + /* REMOVE */ + usbwcm_input(usbwcmp, mp0); + mp0 = mp0->b_cont; + } while (mp0 != NULL); /* next block, if any */ + } + + freemsg(mp); + break; + + case M_CTL: + usbwcm_mctl(q, mp); + return; + + case M_ERROR: + /* REMOVE */ + usbwcmp->usbwcm_flags &= ~USBWCM_QWAIT; + + freemsg(mp); + return; + default: + putnext(q, mp); + return; + } +} + + +static struct module_info modinfo; + +/* STREAMS entry points */ + +/* read side queue */ +static struct qinit rinit = { + (int (*)())usbwcm_rput, /* put procedure not needed */ + NULL, /* service procedure */ + usbwcm_open, /* called on startup */ + usbwcm_close, /* called on finish */ + NULL, /* for future use */ + &modinfo, /* module information structure */ + NULL /* module statistics structure */ +}; + +/* write side queue */ +static struct qinit winit = { + usbwcm_wput, /* put procedure */ + NULL, /* no service proecedure needed */ + NULL, /* open not used on write side */ + NULL, /* close not used on write side */ + NULL, /* for future use */ + &modinfo, /* module information structure */ + NULL /* module statistics structure */ +}; + +/* STREAMS table */ +static struct streamtab strtab = { + &rinit, + &winit, + NULL, /* not a MUX */ + NULL /* not a MUX */ +}; + +/* Module linkage information */ + +static struct fmodsw modsw = { + "usbwcm", + &strtab, + D_MP | D_MTPERMOD +}; + + +static struct modlstrmod modlstr = { + &mod_strmodops, + "USB Wacom STRMOD", + &modsw +}; + +static struct modlinkage modlink = { + MODREV_1, + (void *)&modlstr, + NULL +}; + +static struct module_info modinfo = { + 0x0ffff, /* module id number */ + "usbwcm", /* module name */ + 0, /* min packet size accepted */ + INFPSZ, /* max packet size accepted */ + 512, /* hi-water mark */ + 128 /* lo-water mark */ +}; + + +/* Module entry points */ + +int +_init(void) +{ + int rval = mod_install(&modlink); + + if (rval == 0) { + usbwcm_log_handle = usb_alloc_log_hdl(NULL, "usbwcm", + &usbwcm_errlevel, &usbwcm_errmask, NULL, 0); + } + + return (rval); +} + +int +_fini(void) +{ + int rval = mod_remove(&modlink); + + if (rval == 0) { + usb_free_log_hdl(usbwcm_log_handle); + } + + return (rval); +} + +int +_info(struct modinfo *modinfop) +{ + + return (mod_info(&modlink, modinfop)); +}
--- a/usr/src/uts/common/sys/Makefile Wed Jan 13 19:48:54 2010 -0800 +++ b/usr/src/uts/common/sys/Makefile Thu Jan 14 17:07:01 2010 +0800 @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Copyright 2010 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -1008,6 +1008,9 @@ USBVIDHDRS= \ usbvc.h +USBWCMHDRS= \ + usbwcm.h + UGENHDRS= \ usb_ugen.h @@ -1159,6 +1162,7 @@ $(USBPRNHDRS:%.h=usb/clients/printer/%.check) \ $(USBCDCHDRS:%.h=usb/clients/usbcdc/%.check) \ $(USBVIDHDRS:%.h=usb/clients/video/usbvc/%.check) \ + $(USBWCMHDRS:%.h=usb/clients/usbinput/usbwcm/%.check) \ $(UGENHDRS:%.h=usb/clients/ugen/%.check) \ $(USBHDRS:%.h=usb/%.check) \ $(UWBHDRS:%.h=uwb/%.check) \ @@ -1222,6 +1226,7 @@ $(ROOTUSBPRNHDRS) \ $(ROOTUSBCDCHDRS) \ $(ROOTUSBVIDHDRS) \ + $(ROOTUSBWCMHDRS) \ $(ROOTUGENHDRS) \ $(ROOT1394HDRS) \ $(ROOTHOTPLUGHDRS) \ @@ -1284,6 +1289,7 @@ $(ROOTUSBPRNHDRS) \ $(ROOTUSBCDCHDRS) \ $(ROOTUSBVIDHDRS) \ + $(ROOTUSBWCMHDRS) \ $(ROOTUGENHDRS) \ $(ROOT1394HDRS) \ $(ROOTHOTPLUGHDRS) \
--- a/usr/src/uts/common/sys/Makefile.syshdrs Wed Jan 13 19:48:54 2010 -0800 +++ b/usr/src/uts/common/sys/Makefile.syshdrs Thu Jan 14 17:07:01 2010 +0800 @@ -18,7 +18,7 @@ # # CDDL HEADER END # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Copyright 2010 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -131,9 +131,6 @@ usb/clients/mass_storage/%.check: usb/clients/mass_storage/%.h $(DOT_H_CHECK) -usb/clients/hid/%.check: usb/clients/hid/%.h - $(DOT_H_CHECK) - usb/clients/printer/%.check: usb/clients/printer/%.h $(DOT_H_CHECK) @@ -143,6 +140,9 @@ usb/clients/video/usbvc/%.check: usb/clients/video/usbvc/%.h $(DOT_H_CHECK) +usb/clients/usbinput/usbwcm/%.check: usb/clients/usbinput/usbwcm/%.h + $(DOT_H_CHECK) + 1394/%.check: 1394/%.h $(DOT_H_CHECK) @@ -210,6 +210,7 @@ $(ROOTDIR)/usb/clients/printer \ $(ROOTDIR)/usb/clients/usbcdc \ $(ROOTDIR)/usb/clients/video/usbvc \ + $(ROOTDIR)/usb/clients/usbinput/usbwcm \ $(ROOTDIR)/usb/clients/ugen \ $(ROOTDIR)/uwb \ $(ROOTDIR)/uwb/uwba \ @@ -291,6 +292,7 @@ ROOTUSBPRNHDRS= $(USBPRNHDRS:%=$(ROOTDIR)/usb/clients/printer/%) ROOTUSBCDCHDRS= $(USBCDCHDRS:%=$(ROOTDIR)/usb/clients/usbcdc/%) ROOTUSBVIDHDRS= $(USBVIDHDRS:%=$(ROOTDIR)/usb/clients/video/usbvc/%) +ROOTUSBWCMHDRS= $(USBWCMHDRS:%=$(ROOTDIR)/usb/clients/usbinput/usbwcm/%) ROOTUGENHDRS= $(UGENHDRS:%=$(ROOTDIR)/usb/clients/ugen/%) ROOT1394HDRS= $(I1394HDRS:%=$(ROOTDIR)/1394/%)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/sys/usb/clients/usbinput/usbwcm/usbwcm.h Thu Jan 14 17:07:01 2010 +0800 @@ -0,0 +1,465 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Copyright (c) 2007, 2008 Bartosz Fabianowski <freebsd@chillt.de> + * All rights reserved. + * + * Financed by the "Irish Research Council for Science, Engineering and + * Technology: funded by the National Development Plan" + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Lennart Augustsson (lennart@augustsson.net) at + * Carlstedt Research & Technology. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SYS_USB_USBWCM_H +#define _SYS_USB_USBWCM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/ioccom.h> +#if defined(_LP64) || defined(_I32LPx) +#include <sys/types32.h> +#else +#include <sys/types.h> +#endif +#include <sys/time.h> + +#define EVTIOCGVERSION _IOR('E', 0x1, int) +#define EVTIOCGDEVID _IOR('E', 0x2, struct event_dev_id) +#define EVTIOCGBM(i, s) _IORN('E', 0x20 + (i), (s)) +#define EVTIOCGABS(i) _IOR('E', 0x40 + (i), struct event_abs_axis) +#define EVTIOC ('E' << 8) + +struct event_dev_id { + uint16_t bus; +#define ID_BUS_USB 3 + uint16_t vendor; + uint16_t product; + uint16_t version; +}; + +struct event_abs_axis { + int32_t value; + int32_t min; + int32_t max; + int32_t fuzz; + int32_t flat; +}; + +struct event_input { +#if defined(_LP64) || defined(_I32LPx) + struct timeval32 time; +#else + struct timeval time; +#endif + uint16_t type; + uint16_t code; + int32_t value; +}; + +#define EVT_SYN 0x0000 +#define EVT_BTN 0x0001 +#define EVT_REL 0x0002 +#define EVT_ABS 0x0003 +#define EVT_MSC 0x0004 +#define EVT_USED 0x0005 +#define EVT_MAX 0x001f + +#define SYN_REPORT 0x0000 + +#define BTN_MISC_0 0x0100 +#define BTN_MISC_1 0x0101 +#define BTN_MISC_2 0x0102 +#define BTN_MISC_3 0x0103 +#define BTN_MISC_4 0x0104 +#define BTN_MISC_5 0x0105 +#define BTN_MISC_6 0x0106 +#define BTN_MISC_7 0x0107 +#define BTN_MISC_8 0x0108 + +#define BTN_LEFT 0x0110 +#define BTN_RIGHT 0x0111 +#define BTN_MIDDLE 0x0112 +#define BTN_SIDE 0x0113 +#define BTN_EXTRA 0x0114 +#define BTN_TOOL_PEN 0x0140 +#define BTN_TOOL_ERASER 0x0141 +#define BTN_TOOL_PAD 0x0145 +#define BTN_TOOL_MOUSE 0x0146 +#define BTN_TIP 0x014a +#define BTN_STYLUS_1 0x014b +#define BTN_STYLUS_2 0x014c +#define BTN_USED 0x014d +#define BTN_MISC_UND 0x01ff +#define BTN_MAX 0x01ff + +#define REL_WHEEL 0x0008 +#define REL_MAX 0x000f + +#define ABS_X 0x0000 +#define ABS_Y 0x0001 +#define ABS_Z 0x0002 +#define ABS_RX 0x0003 +#define ABS_RY 0x0004 +#define ABS_RZ 0x0005 + +#define ABS_WHEEL 0x0008 +#define ABS_PRESSURE 0x0018 +#define ABS_DISTANCE 0x0019 +#define ABS_TILT_X 0x001a +#define ABS_TILT_Y 0x001b +#define ABS_MISC 0x0028 +#define ABS_USED 0x0029 +#define ABS_MAX 0x003f + +#define MSC_SERIAL 0x0000 +#define MSC_MAX 0x0007 + +#ifdef _KERNEL +/* USB IDs */ +#define USB_VENDOR_WACOM 0x056a + +#define USB_PRODUCT_WACOM_GRAPHIRE 0x0010 +#define USB_PRODUCT_WACOM_GRAPHIRE2_4X5 0x0011 +#define USB_PRODUCT_WACOM_GRAPHIRE2_5X7 0x0012 +#define USB_PRODUCT_WACOM_GRAPHIRE3_4X5 0x0013 +#define USB_PRODUCT_WACOM_GRAPHIRE3_6X8 0x0014 +#define USB_PRODUCT_WACOM_GRAPHIRE4_4X5 0x0015 +#define USB_PRODUCT_WACOM_GRAPHIRE4_6X8 0x0016 +#define USB_PRODUCT_WACOM_BAMBOO_FUN_4X5 0x0017 +#define USB_PRODUCT_WACOM_BAMBOO_FUN_6X8 0x0018 +#define USB_PRODUCT_WACOM_BAMBOO_ONE_6X8 0x0019 +#define USB_PRODUCT_WACOM_CINTIQ_21UX 0x003f +#define USB_PRODUCT_WACOM_VOLITO 0x0060 +#define USB_PRODUCT_WACOM_PENSTATION2 0x0061 +#define USB_PRODUCT_WACOM_VOLITO2_4X5 0x0062 +#define USB_PRODUCT_WACOM_VOLITO2_2X3 0x0063 +#define USB_PRODUCT_WACOM_PENPARTNER2 0x0064 +#define USB_PRODUCT_WACOM_BAMBOO 0x0065 +#define USB_PRODUCT_WACOM_BAMBOO_ONE_4X5 0x0069 +#define USB_PRODUCT_WACOM_INTUOS3_4X5 0x00b0 +#define USB_PRODUCT_WACOM_INTUOS3_6X8 0x00b1 +#define USB_PRODUCT_WACOM_INTUOS3_9X12 0x00b2 +#define USB_PRODUCT_WACOM_INTUOS3_12X12 0x00b3 +#define USB_PRODUCT_WACOM_INTUOS3_12X19 0x00b4 +#define USB_PRODUCT_WACOM_INTUOS3_6X11 0x00b5 +#define USB_PRODUCT_WACOM_INTUOS3_4X6 0x00b7 + +#define USB_PRODUCT_WACOM_INTUOS4_4X6 0x00b8 +#define USB_PRODUCT_WACOM_INTUOS4_6X9 0x00b9 +#define USB_PRODUCT_WACOM_INTUOS4_8X13 0x00ba +#define USB_PRODUCT_WACOM_INTUOS4_12X19 0x00bb + +#define TOOL_ID_PEN 0x0002 +#define TOOL_ID_MOUSE 0x0006 +#define TOOL_ID_ERASER 0x000a +#define TOOL_ID_PAD 0x000f + +#define SERIAL_PAD_INTUOS 0xffffffff +#define SERIAL_PAD_GRAPHIRE4 0x000000f0 + +#define EUWACOMGETVERSION 0x01 +#define EUWACOMGETID 0x02 +#define EUWACOMGETBM 0x20 +#define EUWACOMGETABS 0x40 + +/* Protocols */ +struct uwacom_protocol_type { + int packet_size; + int distance_max; +}; + +enum uwacom_protocol { + /* Graphire family */ + GRAPHIRE = 0, + GRAPHIRE4, + MYOFFICE, + + /* Intuos family */ + INTUOS3S, + INTUOS3L, + INTUOS4S, + INTUOS4L, + CINTIQ +}; + +struct uwacom_id { + uint16_t vid; + uint16_t pid; +}; + +/* Models */ +struct uwacom_type { + struct uwacom_id devno; + enum uwacom_protocol protocol; + int x_max; + int y_max; + int pressure_max; +}; + +static const struct uwacom_protocol_type uwacom_protocols[] = { + { 8, 63}, + { 8, 63}, + { 9, 63}, + {10, 63}, + {10, 63}, + {10, 63}, + {10, 63}, + {10, 63} +}; + +struct uwacom_softc { + const struct uwacom_type *sc_type; + struct event_dev_id sc_id; + unsigned long *sc_bm[EVT_USED]; + + int *sc_btn; + struct event_abs_axis *sc_abs; + int sc_tool[2]; + int sc_tool_id[2]; + unsigned int sc_serial[2]; + int sc_sync; +}; + +typedef struct usbwcm_state { + queue_t *usbwcm_rq; /* pointer to read queue */ + queue_t *usbwcm_wq; /* pointer to write queue */ + + int32_t usbwcm_flags; /* open/qwait status */ +#define USBWCM_OPEN 0x00000001 /* opened for business */ +#define USBWCM_QWAIT 0x00000002 /* waiting for a response */ + + /* software state */ + struct uwacom_softc usbwcm_softc; + + /* device model data */ + hid_vid_pid_t usbwcm_devid; + + /* + * Is an ioctl fails because an mblk wasn't + * available, the mlbk is saved here. + */ + mblk_t *usbwcm_mioctl; + bufcall_id_t usbwcm_bufcall; /* id returned by bufcall() */ +} usbwcm_state_t; + +#define abs(x) ((x) < 0 ? -(x) : (x)) + +typedef struct usbwcm_copyin_s { + caddr_t addr; + int state; +#define USBWCM_GETSTRUCT 1 +#define USBWCM_GETRESULT 2 +} usbwcm_copyin_t; + +static const struct uwacom_type uwacom_devs[] = { + { + {USB_VENDOR_WACOM, USB_PRODUCT_WACOM_GRAPHIRE}, + GRAPHIRE, 10206, 7422, 511 + }, + { + {USB_VENDOR_WACOM, USB_PRODUCT_WACOM_GRAPHIRE2_4X5}, + GRAPHIRE, 10206, 7422, 511 + }, + { + {USB_VENDOR_WACOM, USB_PRODUCT_WACOM_GRAPHIRE2_5X7}, + GRAPHIRE, 13918, 10206, 511 + }, + { + {USB_VENDOR_WACOM, USB_PRODUCT_WACOM_GRAPHIRE3_4X5}, + GRAPHIRE, 10208, 7424, 511 + }, + { + {USB_VENDOR_WACOM, USB_PRODUCT_WACOM_GRAPHIRE3_6X8}, + GRAPHIRE, 16704, 12064, 511 + }, + { + {USB_VENDOR_WACOM, USB_PRODUCT_WACOM_GRAPHIRE4_4X5}, + GRAPHIRE4, 10208, 7424, 511 + }, + { + {USB_VENDOR_WACOM, USB_PRODUCT_WACOM_GRAPHIRE4_6X8}, + GRAPHIRE4, 16704, 12064, 511 + }, + { + {USB_VENDOR_WACOM, USB_PRODUCT_WACOM_BAMBOO_FUN_4X5}, + MYOFFICE, 14760, 9225, 511 + }, + { + {USB_VENDOR_WACOM, USB_PRODUCT_WACOM_BAMBOO_FUN_6X8}, + MYOFFICE, 21648, 13530, 511 + }, + { + {USB_VENDOR_WACOM, USB_PRODUCT_WACOM_BAMBOO_ONE_6X8}, + GRAPHIRE, 16704, 12064, 511 + }, + { + {USB_VENDOR_WACOM, USB_PRODUCT_WACOM_CINTIQ_21UX}, + CINTIQ, 87200, 65600, 1023 + }, + { + {USB_VENDOR_WACOM, USB_PRODUCT_WACOM_VOLITO}, + GRAPHIRE, 5104, 3712, 511 + }, + { + {USB_VENDOR_WACOM, USB_PRODUCT_WACOM_PENSTATION2}, + GRAPHIRE, 3250, 2320, 255 + }, + { + {USB_VENDOR_WACOM, USB_PRODUCT_WACOM_VOLITO2_4X5}, + GRAPHIRE, 5104, 3712, 511 + }, + { + {USB_VENDOR_WACOM, USB_PRODUCT_WACOM_VOLITO2_2X3}, + GRAPHIRE, 3248, 2320, 511 + }, + { + {USB_VENDOR_WACOM, USB_PRODUCT_WACOM_PENPARTNER2}, + GRAPHIRE, 3250, 2320, 511 + }, + { + {USB_VENDOR_WACOM, USB_PRODUCT_WACOM_BAMBOO}, + MYOFFICE, 14760, 9225, 511 + }, + { + {USB_VENDOR_WACOM, USB_PRODUCT_WACOM_BAMBOO_ONE_4X5}, + GRAPHIRE, 5104, 3712, 511 + }, + { + {USB_VENDOR_WACOM, USB_PRODUCT_WACOM_INTUOS3_4X5}, + INTUOS3S, 25400, 20320, 1023 + }, + { + {USB_VENDOR_WACOM, USB_PRODUCT_WACOM_INTUOS3_6X8}, + INTUOS3L, 40640, 30480, 1023 + }, + { + {USB_VENDOR_WACOM, USB_PRODUCT_WACOM_INTUOS3_9X12}, + INTUOS3L, 60960, 45720, 1023 + }, + { + {USB_VENDOR_WACOM, USB_PRODUCT_WACOM_INTUOS3_12X12}, + INTUOS3L, 60960, 60960, 1023 + }, + { + {USB_VENDOR_WACOM, USB_PRODUCT_WACOM_INTUOS3_12X19}, + INTUOS3L, 97536, 60960, 1023 + }, + { + {USB_VENDOR_WACOM, USB_PRODUCT_WACOM_INTUOS3_6X11}, + INTUOS3L, 54204, 31750, 1023 + }, + { + {USB_VENDOR_WACOM, USB_PRODUCT_WACOM_INTUOS3_4X6}, + INTUOS3S, 31496, 19685, 1023 + }, + { + {USB_VENDOR_WACOM, USB_PRODUCT_WACOM_INTUOS4_4X6}, + INTUOS4S, 31496, 19685, 2047 + }, + { + {USB_VENDOR_WACOM, USB_PRODUCT_WACOM_INTUOS4_6X9}, + INTUOS4L, 44704, 27940, 2047 + }, + { + {USB_VENDOR_WACOM, USB_PRODUCT_WACOM_INTUOS4_8X13}, + INTUOS4L, 65024, 40640, 2047 + }, + { + {USB_VENDOR_WACOM, USB_PRODUCT_WACOM_INTUOS4_12X19}, + INTUOS4L, 97536, 60960, 2047 + }, + {{0, 0}, 0, 0, 0, 0} +}; + +#define PACKET_BIT(b, s) ((packet[b] >> (s)) & 1) +#define PACKET_BITS(b, s, n) \ + ((((s) + (n) > 32 ? ((packet[(b) - 4]) << (32 - (s))) : 0) | \ + ((s) + (n) > 24 ? ((packet[(b) - 3]) << (24 - (s))) : 0) | \ + ((s) + (n) > 16 ? ((packet[(b) - 2]) << (16 - (s))) : 0) | \ + ((s) + (n) > 8 ? ((packet[(b) - 1]) << (8 - (s))) : 0) | \ + ((packet[(b)]) >> (s))) & \ + ((n) == 32 ? 0xffffffff : (1 << (n)) - 1)) + +#define BM_SIZE(x) \ + (((x) / (sizeof (long) * 8) + 1) * sizeof (long)) +#define BM_SET_BIT(x, y) \ + ((x)[(y) / (sizeof (long) * 8)] |= (1ul << ((y) % (sizeof (long) * 8)))) + +static const size_t bm_size[EVT_USED] = { + BM_SIZE(EVT_MAX), + BM_SIZE(BTN_MAX), + BM_SIZE(REL_MAX), + BM_SIZE(ABS_MAX), + BM_SIZE(MSC_MAX), +}; + +#define PRINT_MASK_ALL 0xFFFFFFFF + +#endif /* _KERNEL */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_USB_USBWCM_H */
--- a/usr/src/uts/intel/Makefile.intel.shared Wed Jan 13 19:48:54 2010 -0800 +++ b/usr/src/uts/intel/Makefile.intel.shared Thu Jan 14 17:07:01 2010 +0800 @@ -20,7 +20,7 @@ # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Copyright 2010 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -547,6 +547,7 @@ STRMOD_KMODS += tirdwr ttcompat STRMOD_KMODS += usbkbm STRMOD_KMODS += usbms +STRMOD_KMODS += usbwcm STRMOD_KMODS += usb_ah STRMOD_KMODS += drcompat STRMOD_KMODS += cryptmod
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/intel/usbwcm/Makefile Thu Jan 14 17:07:01 2010 +0800 @@ -0,0 +1,98 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# uts/intel/usbwcm/Makefile +# Copyright 2010 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# +# This makefile drives the production of the usbwcm kernel module. +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../.. + +# +# Define the module and object file sets. +# +MODULE = usbwcm +OBJECTS = $(USBWCM_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(USBWCM_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_STRMOD_DIR)/$(MODULE) + +# +# Include common rules. +# +include $(UTSBASE)/intel/Makefile.intel + +# +# Define targets +# +ALL_TARGET = $(BINARY) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) + +# +# Override defaults to build a unique, local modstubs.o. +# +MODSTUBS_DIR = $(OBJS_DIR) +CLEANFILES += $(MODSTUBS_O) + +# +# depends on misc/usba +# +LDFLAGS += -dy -Nmisc/usba + +# +# For now, disable these lint checks; maintainers should endeavor +# to investigate and remove these for maximum lint coverage. +# Please do not carry these forward to new Makefiles. +# +LINTTAGS += -erroff=E_BAD_PTR_CAST_ALIGN + +# +# Default build targets. +# +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + +# +# Include common targets. +# +include $(UTSBASE)/intel/Makefile.targ +
--- a/usr/src/uts/sparc/Makefile.sparc.shared Wed Jan 13 19:48:54 2010 -0800 +++ b/usr/src/uts/sparc/Makefile.sparc.shared Thu Jan 14 17:07:01 2010 +0800 @@ -20,7 +20,7 @@ # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Copyright 2010 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # This makefile contains the common definitions for all sparc @@ -376,7 +376,7 @@ STRMOD_KMODS += pipemod ptem redirmod rpcmod rlmod telmod timod STRMOD_KMODS += spppasyn spppcomp STRMOD_KMODS += tirdwr ttcompat -STRMOD_KMODS += usbkbm usbms usb_ah +STRMOD_KMODS += usbkbm usbms usbwcm usb_ah STRMOD_KMODS += drcompat STRMOD_KMODS += cryptmod STRMOD_KMODS += vuid3ps2
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/sparc/usbwcm/Makefile Thu Jan 14 17:07:01 2010 +0800 @@ -0,0 +1,97 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# uts/sparc/usbwcm/Makefile + +# Copyright 2010 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# +# This makefile drives the production of the usbwcm streams module. +# +# sparc architecture dependent +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../.. + +# +# Define the module and object file sets. +# +MODULE = usbwcm +OBJECTS = $(USBWCM_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(USBWCM_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_STRMOD_DIR)/$(MODULE) + +# +# Include common rules. +# +include $(UTSBASE)/sparc/Makefile.sparc + +# +# lint pass one enforcement +# +CFLAGS += $(CCVERBOSE) + +# +# depends on misc/usba +# +LDFLAGS += -dy -Nmisc/usba + +# +# Define targets +# +ALL_TARGET = $(BINARY) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) + +# +# For now, disable these lint checks; maintainers should endeavor +# to investigate and remove these for maximum lint coverage. +# Please do not carry these forward to new Makefiles. +# +LINTTAGS += -erroff=E_BAD_PTR_CAST_ALIGN + +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + + +# +# Include common targets. +# +include $(UTSBASE)/sparc/Makefile.targ