1*c7fb772bSthorpej /* $NetBSD: uep.c,v 1.25 2021/08/07 16:19:17 thorpej Exp $ */
26cf367d3Stsarna
36cf367d3Stsarna /*
46cf367d3Stsarna * Copyright (c) 2004 The NetBSD Foundation, Inc.
56cf367d3Stsarna * All rights reserved.
66cf367d3Stsarna *
76cf367d3Stsarna * This code is derived from software contributed to The NetBSD Foundation
86cf367d3Stsarna * by Tyler C. Sarna (tsarna@netbsd.org).
96cf367d3Stsarna *
106cf367d3Stsarna * Redistribution and use in source and binary forms, with or without
116cf367d3Stsarna * modification, are permitted provided that the following conditions
126cf367d3Stsarna * are met:
136cf367d3Stsarna * 1. Redistributions of source code must retain the above copyright
146cf367d3Stsarna * notice, this list of conditions and the following disclaimer.
156cf367d3Stsarna * 2. Redistributions in binary form must reproduce the above copyright
166cf367d3Stsarna * notice, this list of conditions and the following disclaimer in the
176cf367d3Stsarna * documentation and/or other materials provided with the distribution.
186cf367d3Stsarna *
196cf367d3Stsarna * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
206cf367d3Stsarna * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
216cf367d3Stsarna * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
226cf367d3Stsarna * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
236cf367d3Stsarna * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
246cf367d3Stsarna * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
256cf367d3Stsarna * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
266cf367d3Stsarna * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
276cf367d3Stsarna * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
286cf367d3Stsarna * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
296cf367d3Stsarna * POSSIBILITY OF SUCH DAMAGE.
306cf367d3Stsarna */
316cf367d3Stsarna
324605dd74Stsarna /*
334605dd74Stsarna * eGalax USB touchpanel controller driver.
344605dd74Stsarna */
356cf367d3Stsarna #include <sys/cdefs.h>
36*c7fb772bSthorpej __KERNEL_RCSID(0, "$NetBSD: uep.c,v 1.25 2021/08/07 16:19:17 thorpej Exp $");
376cf367d3Stsarna
386cf367d3Stsarna #include <sys/param.h>
396cf367d3Stsarna #include <sys/systm.h>
406cf367d3Stsarna #include <sys/kernel.h>
414e8e6643Sskrll #include <sys/kmem.h>
426cf367d3Stsarna #include <sys/device.h>
436cf367d3Stsarna #include <sys/ioctl.h>
446cf367d3Stsarna #include <sys/vnode.h>
456cf367d3Stsarna
466cf367d3Stsarna #include <dev/usb/usb.h>
476cf367d3Stsarna #include <dev/usb/usbdi.h>
486cf367d3Stsarna #include <dev/usb/usbdi_util.h>
496cf367d3Stsarna #include <dev/usb/usbdevs.h>
506cf367d3Stsarna #include <dev/usb/usb_quirks.h>
516cf367d3Stsarna
526cf367d3Stsarna #include <dev/wscons/wsconsio.h>
536cf367d3Stsarna #include <dev/wscons/wsmousevar.h>
544605dd74Stsarna #include <dev/wscons/tpcalibvar.h>
554605dd74Stsarna
564605dd74Stsarna #define UIDSTR "eGalax USB SN000000"
572da1fe54Smaya /* calibration - integer values, perhaps sysctls? */
582da1fe54Smaya #define X_RATIO 293
592da1fe54Smaya #define X_OFFSET -28
602da1fe54Smaya #define Y_RATIO -348
612da1fe54Smaya #define Y_OFFSET 537
622da1fe54Smaya /* an X_RATIO of ``312'' means : reduce by a factor 3.12 x axis amplitude */
632da1fe54Smaya /* an Y_RATIO of ``-157'' means : reduce by a factor 1.57 y axis amplitude,
642da1fe54Smaya * and reverse y motion */
656cf367d3Stsarna
666cf367d3Stsarna struct uep_softc {
6749337c88Sdyoung device_t sc_dev;
684e8e6643Sskrll struct usbd_device *sc_udev; /* device */
694e8e6643Sskrll struct usbd_interface *sc_iface; /* interface */
706cf367d3Stsarna int sc_iface_number;
716cf367d3Stsarna
726cf367d3Stsarna int sc_intr_number; /* interrupt number */
734e8e6643Sskrll struct usbd_pipe * sc_intr_pipe; /* interrupt pipe */
746cf367d3Stsarna u_char *sc_ibuf;
756cf367d3Stsarna int sc_isize;
766cf367d3Stsarna
7749337c88Sdyoung device_t sc_wsmousedev; /* wsmouse device */
784605dd74Stsarna struct tpcalib_softc sc_tpcalib; /* calibration */
796cf367d3Stsarna
806cf367d3Stsarna u_char sc_enabled;
816cf367d3Stsarna u_char sc_dying;
826cf367d3Stsarna };
836cf367d3Stsarna
844605dd74Stsarna static struct wsmouse_calibcoords default_calib = {
8508a78fe1Schristos .minx = 0,
8608a78fe1Schristos .miny = 0,
8708a78fe1Schristos .maxx = 2047,
8808a78fe1Schristos .maxy = 2047,
8908a78fe1Schristos .samplelen = WSMOUSE_CALIBCOORDS_RESET,
904605dd74Stsarna };
914605dd74Stsarna
924e8e6643Sskrll Static void uep_intr(struct usbd_xfer *, void *, usbd_status);
936cf367d3Stsarna
946cf367d3Stsarna Static int uep_enable(void *);
956cf367d3Stsarna Static void uep_disable(void *);
9653524e44Schristos Static int uep_ioctl(void *, u_long, void *, int, struct lwp *);
976cf367d3Stsarna
9897b908dcSmaxv static const struct wsmouse_accessops uep_accessops = {
996cf367d3Stsarna uep_enable,
1006cf367d3Stsarna uep_ioctl,
1016cf367d3Stsarna uep_disable,
1026cf367d3Stsarna };
1036cf367d3Stsarna
10497b908dcSmaxv static int uep_match(device_t, cfdata_t, void *);
10597b908dcSmaxv static void uep_attach(device_t, device_t, void *);
10697b908dcSmaxv static void uep_childdet(device_t, device_t);
10797b908dcSmaxv static int uep_detach(device_t, int);
10897b908dcSmaxv static int uep_activate(device_t, enum devact);
1093b24a134Smrg
1103624455eScube CFATTACH_DECL2_NEW(uep, sizeof(struct uep_softc), uep_match, uep_attach,
1110b1dce29Sdyoung uep_detach, uep_activate, NULL, uep_childdet);
1126cf367d3Stsarna
11397b908dcSmaxv static int
uep_match(device_t parent,cfdata_t match,void * aux)11449337c88Sdyoung uep_match(device_t parent, cfdata_t match, void *aux)
1156cf367d3Stsarna {
11649337c88Sdyoung struct usb_attach_arg *uaa = aux;
1176cf367d3Stsarna
1184e8e6643Sskrll if ((uaa->uaa_vendor == USB_VENDOR_EGALAX) && (
1194e8e6643Sskrll (uaa->uaa_product == USB_PRODUCT_EGALAX_TPANEL)
1204e8e6643Sskrll || (uaa->uaa_product == USB_PRODUCT_EGALAX_TPANEL2)))
1216cf367d3Stsarna return UMATCH_VENDOR_PRODUCT;
1226cf367d3Stsarna
1234e8e6643Sskrll if ((uaa->uaa_vendor == USB_VENDOR_EGALAX2)
1244e8e6643Sskrll && (uaa->uaa_product == USB_PRODUCT_EGALAX2_TPANEL))
1256cf367d3Stsarna return UMATCH_VENDOR_PRODUCT;
1266cf367d3Stsarna
1276cf367d3Stsarna
1286cf367d3Stsarna return UMATCH_NONE;
1296cf367d3Stsarna }
1306cf367d3Stsarna
13197b908dcSmaxv static void
uep_attach(device_t parent,device_t self,void * aux)13249337c88Sdyoung uep_attach(device_t parent, device_t self, void *aux)
1336cf367d3Stsarna {
13449337c88Sdyoung struct uep_softc *sc = device_private(self);
13549337c88Sdyoung struct usb_attach_arg *uaa = aux;
1364e8e6643Sskrll struct usbd_device *dev = uaa->uaa_device;
1376cf367d3Stsarna usb_config_descriptor_t *cdesc;
1386cf367d3Stsarna usb_interface_descriptor_t *id;
1396cf367d3Stsarna usb_endpoint_descriptor_t *ed;
140e88e0045Smbalmer usb_device_request_t req;
141e88e0045Smbalmer uByte act;
1426cf367d3Stsarna struct wsmousedev_attach_args a;
143834327c8Saugustss char *devinfop;
1446cf367d3Stsarna usbd_status err;
145d78264e0Smartin int i;
1466cf367d3Stsarna
1473624455eScube sc->sc_dev = self;
1485fab894cSplunky
1495fab894cSplunky aprint_naive("\n");
1505fab894cSplunky aprint_normal("\n");
1515fab894cSplunky
152834327c8Saugustss devinfop = usbd_devinfo_alloc(dev, 0);
1533624455eScube aprint_normal_dev(self, "%s\n", devinfop);
154834327c8Saugustss usbd_devinfo_free(devinfop);
1556cf367d3Stsarna sc->sc_udev = dev;
1566cf367d3Stsarna sc->sc_intr_number = -1;
1576cf367d3Stsarna sc->sc_intr_pipe = NULL;
1586cf367d3Stsarna sc->sc_enabled = sc->sc_isize = 0;
1596cf367d3Stsarna
1606cf367d3Stsarna /* Move the device into the configured state. */
1616cf367d3Stsarna err = usbd_set_config_index(dev, 0, 1);
1626cf367d3Stsarna if (err) {
1633624455eScube aprint_error("\n%s: failed to set configuration, err=%s\n",
16449337c88Sdyoung device_xname(sc->sc_dev), usbd_errstr(err));
1656cf367d3Stsarna sc->sc_dying = 1;
16649337c88Sdyoung return;
1676cf367d3Stsarna }
1686cf367d3Stsarna
1696cf367d3Stsarna /* get the config descriptor */
1706cf367d3Stsarna cdesc = usbd_get_config_descriptor(sc->sc_udev);
1716cf367d3Stsarna if (cdesc == NULL) {
1723624455eScube aprint_error_dev(self,
1733624455eScube "failed to get configuration descriptor\n");
1746cf367d3Stsarna sc->sc_dying = 1;
17549337c88Sdyoung return;
1766cf367d3Stsarna }
1776cf367d3Stsarna
1786cf367d3Stsarna /* get the interface */
1796cf367d3Stsarna err = usbd_device2interface_handle(dev, 0, &sc->sc_iface);
1806cf367d3Stsarna if (err) {
1813624455eScube aprint_error("\n%s: failed to get interface, err=%s\n",
18249337c88Sdyoung device_xname(sc->sc_dev), usbd_errstr(err));
1836cf367d3Stsarna sc->sc_dying = 1;
18449337c88Sdyoung return;
1856cf367d3Stsarna }
1866cf367d3Stsarna
1876cf367d3Stsarna /* Find the interrupt endpoint */
1886cf367d3Stsarna id = usbd_get_interface_descriptor(sc->sc_iface);
1896cf367d3Stsarna sc->sc_iface_number = id->bInterfaceNumber;
1906cf367d3Stsarna
1916cf367d3Stsarna for (i = 0; i < id->bNumEndpoints; i++) {
1926cf367d3Stsarna ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
1936cf367d3Stsarna if (ed == NULL) {
1943624455eScube aprint_error_dev(self,
1953624455eScube "no endpoint descriptor for %d\n", i);
1966cf367d3Stsarna sc->sc_dying = 1;
19749337c88Sdyoung return;
1986cf367d3Stsarna }
1996cf367d3Stsarna
2006cf367d3Stsarna if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
2016cf367d3Stsarna UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
2026cf367d3Stsarna sc->sc_intr_number = ed->bEndpointAddress;
2036cf367d3Stsarna sc->sc_isize = UGETW(ed->wMaxPacketSize);
2046cf367d3Stsarna }
2056cf367d3Stsarna }
2066cf367d3Stsarna
2076cf367d3Stsarna if (sc->sc_intr_number== -1) {
2083624455eScube aprint_error_dev(self, "Could not find interrupt in\n");
2096cf367d3Stsarna sc->sc_dying = 1;
21049337c88Sdyoung return;
2116cf367d3Stsarna }
2126cf367d3Stsarna
213e88e0045Smbalmer /* Newer controllers need an activation command */
214e88e0045Smbalmer req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
215e88e0045Smbalmer req.bRequest = 0x0a;
216e88e0045Smbalmer USETW(req.wValue, 'A');
217e88e0045Smbalmer USETW(req.wIndex, 0);
218e88e0045Smbalmer USETW(req.wLength, 1);
219e88e0045Smbalmer usbd_do_request(dev, &req, &act);
220e88e0045Smbalmer
221e88e0045Smbalmer usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, sc->sc_dev);
2226cf367d3Stsarna
2236cf367d3Stsarna a.accessops = &uep_accessops;
2246cf367d3Stsarna a.accesscookie = sc;
2256cf367d3Stsarna
226*c7fb772bSthorpej sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint, CFARGS_NONE);
2276cf367d3Stsarna
2284605dd74Stsarna tpcalib_init(&sc->sc_tpcalib);
2294605dd74Stsarna tpcalib_ioctl(&sc->sc_tpcalib, WSMOUSEIO_SCALIBCOORDS,
23053524e44Schristos (void *)&default_calib, 0, 0);
2314605dd74Stsarna
23249337c88Sdyoung return;
2336cf367d3Stsarna }
2346cf367d3Stsarna
23597b908dcSmaxv static int
uep_detach(device_t self,int flags)23649337c88Sdyoung uep_detach(device_t self, int flags)
2376cf367d3Stsarna {
23849337c88Sdyoung struct uep_softc *sc = device_private(self);
2396cf367d3Stsarna int rv = 0;
2406cf367d3Stsarna
2416cf367d3Stsarna if (sc->sc_intr_pipe != NULL) {
2426cf367d3Stsarna usbd_abort_pipe(sc->sc_intr_pipe);
2436cf367d3Stsarna usbd_close_pipe(sc->sc_intr_pipe);
2446cf367d3Stsarna sc->sc_intr_pipe = NULL;
2456cf367d3Stsarna }
2466cf367d3Stsarna sc->sc_dying = 1;
2476cf367d3Stsarna
2484605dd74Stsarna /* save current calib as defaults */
2494605dd74Stsarna default_calib = sc->sc_tpcalib.sc_saved;
2504605dd74Stsarna
2510b1dce29Sdyoung if (sc->sc_wsmousedev != NULL)
2526cf367d3Stsarna rv = config_detach(sc->sc_wsmousedev, flags);
2536cf367d3Stsarna
254e88e0045Smbalmer usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, sc->sc_dev);
2556cf367d3Stsarna return rv;
2566cf367d3Stsarna }
2576cf367d3Stsarna
25897b908dcSmaxv static void
uep_childdet(device_t self,device_t child)2590b1dce29Sdyoung uep_childdet(device_t self, device_t child)
2606cf367d3Stsarna {
2610b1dce29Sdyoung struct uep_softc *sc = device_private(self);
2620b1dce29Sdyoung
2630b1dce29Sdyoung KASSERT(sc->sc_wsmousedev == child);
2640b1dce29Sdyoung sc->sc_wsmousedev = NULL;
2650b1dce29Sdyoung }
2660b1dce29Sdyoung
26797b908dcSmaxv static int
uep_activate(device_t self,enum devact act)2680b1dce29Sdyoung uep_activate(device_t self, enum devact act)
2690b1dce29Sdyoung {
2700b1dce29Sdyoung struct uep_softc *sc = device_private(self);
2716cf367d3Stsarna
2726cf367d3Stsarna switch (act) {
2736cf367d3Stsarna case DVACT_DEACTIVATE:
2746cf367d3Stsarna sc->sc_dying = 1;
2758d519865Sdyoung return 0;
2768d519865Sdyoung default:
2778d519865Sdyoung return EOPNOTSUPP;
2786cf367d3Stsarna }
2796cf367d3Stsarna }
2806cf367d3Stsarna
2816cf367d3Stsarna Static int
uep_enable(void * v)2826cf367d3Stsarna uep_enable(void *v)
2836cf367d3Stsarna {
2846cf367d3Stsarna struct uep_softc *sc = v;
2856cf367d3Stsarna int err;
2866cf367d3Stsarna
2876cf367d3Stsarna if (sc->sc_dying)
2886cf367d3Stsarna return EIO;
2896cf367d3Stsarna
2906cf367d3Stsarna if (sc->sc_enabled)
2916cf367d3Stsarna return EBUSY;
2926cf367d3Stsarna
2936cf367d3Stsarna if (sc->sc_isize == 0)
2946cf367d3Stsarna return 0;
295e88e0045Smbalmer
2964e8e6643Sskrll sc->sc_ibuf = kmem_alloc(sc->sc_isize, KM_SLEEP);
2976cf367d3Stsarna err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_intr_number,
2986cf367d3Stsarna USBD_SHORT_XFER_OK, &sc->sc_intr_pipe, sc, sc->sc_ibuf,
2996cf367d3Stsarna sc->sc_isize, uep_intr, USBD_DEFAULT_INTERVAL);
3006cf367d3Stsarna if (err) {
3014e8e6643Sskrll kmem_free(sc->sc_ibuf, sc->sc_isize);
3026cf367d3Stsarna sc->sc_intr_pipe = NULL;
3036cf367d3Stsarna return EIO;
3046cf367d3Stsarna }
3056cf367d3Stsarna
3066cf367d3Stsarna sc->sc_enabled = 1;
3076cf367d3Stsarna
3086cf367d3Stsarna return 0;
3096cf367d3Stsarna }
3106cf367d3Stsarna
3116cf367d3Stsarna Static void
uep_disable(void * v)3126cf367d3Stsarna uep_disable(void *v)
3136cf367d3Stsarna {
3146cf367d3Stsarna struct uep_softc *sc = v;
3156cf367d3Stsarna
3166cf367d3Stsarna if (!sc->sc_enabled) {
3176cf367d3Stsarna printf("uep_disable: already disabled!\n");
3186cf367d3Stsarna return;
3196cf367d3Stsarna }
3206cf367d3Stsarna
3216cf367d3Stsarna /* Disable interrupts. */
3226cf367d3Stsarna if (sc->sc_intr_pipe != NULL) {
3236cf367d3Stsarna usbd_abort_pipe(sc->sc_intr_pipe);
3246cf367d3Stsarna usbd_close_pipe(sc->sc_intr_pipe);
3256cf367d3Stsarna sc->sc_intr_pipe = NULL;
3266cf367d3Stsarna }
3276cf367d3Stsarna
3286cf367d3Stsarna if (sc->sc_ibuf != NULL) {
3294e8e6643Sskrll kmem_free(sc->sc_ibuf, sc->sc_isize);
3306cf367d3Stsarna sc->sc_ibuf = NULL;
3316cf367d3Stsarna }
3326cf367d3Stsarna
3336cf367d3Stsarna sc->sc_enabled = 0;
3346cf367d3Stsarna }
3356cf367d3Stsarna
3366cf367d3Stsarna Static int
uep_ioctl(void * v,u_long cmd,void * data,int flag,struct lwp * l)33753524e44Schristos uep_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
3386cf367d3Stsarna {
3394605dd74Stsarna struct uep_softc *sc = v;
3404605dd74Stsarna struct wsmouse_id *id;
3414605dd74Stsarna
3426cf367d3Stsarna switch (cmd) {
3436cf367d3Stsarna case WSMOUSEIO_GTYPE:
3446cf367d3Stsarna *(u_int *)data = WSMOUSE_TYPE_TPANEL;
3454605dd74Stsarna return 0;
3464605dd74Stsarna
3474605dd74Stsarna case WSMOUSEIO_GETID:
3484605dd74Stsarna /*
3494605dd74Stsarna * return unique ID string
3504605dd74Stsarna * "<vendor> <model> <serial number>"
3514605dd74Stsarna * unfortunately we have no serial number...
3524605dd74Stsarna */
3534605dd74Stsarna id = (struct wsmouse_id *)data;
3544605dd74Stsarna if (id->type != WSMOUSE_ID_TYPE_UIDSTR)
3554605dd74Stsarna return EINVAL;
3564605dd74Stsarna
3574605dd74Stsarna strcpy(id->data, UIDSTR);
3584605dd74Stsarna id->length = strlen(UIDSTR);
3594605dd74Stsarna return 0;
3604605dd74Stsarna
3614605dd74Stsarna case WSMOUSEIO_SCALIBCOORDS:
3624605dd74Stsarna case WSMOUSEIO_GCALIBCOORDS:
36395e1ffb1Schristos return tpcalib_ioctl(&sc->sc_tpcalib, cmd, data, flag, l);
3646cf367d3Stsarna }
3656cf367d3Stsarna
3666cf367d3Stsarna return EPASSTHROUGH;
3676cf367d3Stsarna }
3686cf367d3Stsarna
3692da1fe54Smaya static int
uep_adjust(int v,int off,int rat)3702da1fe54Smaya uep_adjust(int v, int off, int rat)
3712da1fe54Smaya {
3722da1fe54Smaya int num = 100 * v;
3732da1fe54Smaya int quot = num / rat;
3742da1fe54Smaya int rem = num % rat;
3752da1fe54Smaya if (num >= 0 && rem < 0)
3762da1fe54Smaya quot++;
3772da1fe54Smaya return quot + off;
3782da1fe54Smaya }
3792da1fe54Smaya
3806cf367d3Stsarna void
uep_intr(struct usbd_xfer * xfer,void * addr,usbd_status status)3814e8e6643Sskrll uep_intr(struct usbd_xfer *xfer, void *addr, usbd_status status)
3826cf367d3Stsarna {
3836cf367d3Stsarna struct uep_softc *sc = addr;
3846cf367d3Stsarna u_char *p = sc->sc_ibuf;
385e88e0045Smbalmer u_char msk;
3864e8e6643Sskrll uint32_t len;
3876cf367d3Stsarna int x = 0, y = 0, s;
3886cf367d3Stsarna
3896cf367d3Stsarna usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL);
3906cf367d3Stsarna
3916cf367d3Stsarna if (status == USBD_CANCELLED)
3926cf367d3Stsarna return;
3936cf367d3Stsarna
3946cf367d3Stsarna if (status != USBD_NORMAL_COMPLETION) {
3953624455eScube aprint_error_dev(sc->sc_dev, "status %d\n", status);
3966cf367d3Stsarna usbd_clear_endpoint_stall_async(sc->sc_intr_pipe);
3976cf367d3Stsarna return;
3986cf367d3Stsarna }
3996cf367d3Stsarna
400e88e0045Smbalmer /* First bit is always set to 1 */
401e88e0045Smbalmer if ((p[0] & 0x80) != 0x80) {
402e88e0045Smbalmer aprint_error_dev(sc->sc_dev, "bad input packet format\n");
4036cf367d3Stsarna return;
4046cf367d3Stsarna }
4056cf367d3Stsarna
4066cf367d3Stsarna if (sc->sc_wsmousedev != NULL) {
4074605dd74Stsarna /*
408e88e0045Smbalmer * Each report package may contain 5 or 6 bytes as below:
4094605dd74Stsarna *
410e88e0045Smbalmer * Byte 0 1ZM00HLT
411e88e0045Smbalmer * Byte 1 0AAAAAAA
412e88e0045Smbalmer * Byte 2 0AAAAAAA
413e88e0045Smbalmer * Byte 3 0BBBBBBB
414e88e0045Smbalmer * Byte 4 0BBBBBBB
415e88e0045Smbalmer * Byte 5 0PPPPPPP
4164605dd74Stsarna *
417e88e0045Smbalmer * Z: 1=byte 5 is pressure information, 0=no pressure
418e88e0045Smbalmer * M: 1=byte 5 is play id, 0=no player id
419e88e0045Smbalmer * T: 1=touched, 0=not touched
420e88e0045Smbalmer * H,L: Resolution
421e88e0045Smbalmer * 0,0: 11 bits
422e88e0045Smbalmer * 0,1: 12 bits
423e88e0045Smbalmer * 1,0: 13 bits
424e88e0045Smbalmer * 1,1: 14 bits
4254605dd74Stsarna * A: bits of axis A position, MSB to LSB
4264605dd74Stsarna * B: bits of axis B position, MSB to LSB
4274605dd74Stsarna *
428e88e0045Smbalmer * The packet has six bytes only if Z or M is set.
429e88e0045Smbalmer * Byte 5, if sent, is ignored.
430e88e0045Smbalmer *
4314605dd74Stsarna * For the unit I have, A = Y and B = X.
4324605dd74Stsarna * I don't know if units exist with A=X and B=Y,
4334605dd74Stsarna * if so we'll cross that bridge when we come to it.
4344605dd74Stsarna *
4354605dd74Stsarna * The controller sends a stream of T=1 events while the
4364605dd74Stsarna * panel is touched, followed by a single T=0 event.
4374605dd74Stsarna */
438e88e0045Smbalmer switch (p[0] & 0x06) {
439e88e0045Smbalmer case 0x02:
440e88e0045Smbalmer msk = 0x1f;
441e88e0045Smbalmer break;
442e88e0045Smbalmer case 0x04:
443e88e0045Smbalmer msk = 0x3f;
444e88e0045Smbalmer break;
445e88e0045Smbalmer case 0x06:
446e88e0045Smbalmer msk = 0x7f;
447e88e0045Smbalmer break;
448e88e0045Smbalmer default:
449e88e0045Smbalmer msk = 0x0f; /* H=0, L=0 */
450e88e0045Smbalmer }
4512da1fe54Smaya x = uep_adjust(((p[3] & msk) << 7) | p[4], X_OFFSET, X_RATIO);
4522da1fe54Smaya y = uep_adjust(((p[1] & msk) << 7) | p[2], Y_OFFSET, Y_RATIO);
4536cf367d3Stsarna
4544605dd74Stsarna tpcalib_trans(&sc->sc_tpcalib, x, y, &x, &y);
4556cf367d3Stsarna
4566cf367d3Stsarna s = spltty();
45757c0199dSplunky wsmouse_input(sc->sc_wsmousedev, p[0] & 0x01, x, y, 0, 0,
4586cf367d3Stsarna WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y);
4596cf367d3Stsarna splx(s);
4606cf367d3Stsarna }
4616cf367d3Stsarna }
462