/*- * Copyright (c) 2008-2009, Volker Werth, vwe@ * All rights reserved. * * 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. * * $Id$ */ /*- * utouch.c - handle USB touchscreen devices * * supported devices: * eGalax (@Touch) SAWUSBPA5 + SAWUSBPA52 * GeneralTouch ST6101U * 3M MicroTouch EX-1x1 */ #include #include #include #include #include #include #include #include #include #include "utouch.h" static int utouch_calibrate = 0; SYSCTL_NODE(_debug, OID_AUTO, utouch, CTLFLAG_RW, 0, "USB touchscreen settings"); SYSCTL_INT(_debug_utouch, OID_AUTO, calibrate, CTLFLAG_RW, &utouch_calibrate, 0, "utouch calibration service mode"); #ifdef UTOUCH_DEBUG static int utouch_debug = 0; #define DPRINTF(n,fmt,...) do { if (utouch_debug & n) { \ printf("%s: " fmt, __FUNCTION__,## __VA_ARGS__); } } while (0) SYSCTL_INT(_debug_utouch, OID_AUTO, debug, CTLFLAG_RW, &utouch_debug, 0, "utouch debug level"); TUNABLE_INT("debug.utouch.debug", &utouch_debug); #else #define DPRINTF(...) #endif #define DEV2SC(dev) (dev)->si_drv1 #define UT_BUF_SIZE 16 /* bytes */ #define UT_IFQ_MAXLEN 50 /* units */ #define UT_N_TRANSFER 2 /* units */ #define UT_BUTTON_MAX 1 /* exclusive, must be less than 32 */ /*#define UT_BUT(i) ((i) < 3 ? (((i) + 2) % 3) : (i))*/ #define UT_BUT(i) (((int)(i/2)) + i%2) static const struct usbd_config utouch_config[UT_N_TRANSFER]; struct utouch_softc { struct usb_cdev sc_cdev; struct mtx sc_mtx; #if (__FreeBSD_version >= 700000) struct usb_callout sc_callout; #else struct __callout sc_callout; #endif struct hid_location sc_loc_x; struct hid_location sc_loc_y; struct hid_location sc_loc_z; struct hid_location sc_loc_btn[UT_BUTTON_MAX]; struct usbd_xfer * sc_xfer[UT_N_TRANSFER]; u_int32_t sc_flags; u_int8_t sc_buttons; u_int8_t sc_iid; utouch_status_t sc_touch; touchdecode_t *decoder; }; /* static void utouch_put_queue_timeout(void *__sc); */ static usbd_callback_t utouch_clear_stall_callback; static usbd_callback_t utouch_intr_callback; static device_probe_t utouch_probe; static device_attach_t utouch_attach; static device_detach_t utouch_detach; static void utouch_start_read(struct usb_cdev *cdev); static void utouch_stop_read(struct usb_cdev *cdev); static int32_t utouch_open(struct usb_cdev *cdev, int32_t fflags, int32_t devtype, struct thread *td); static int32_t utouch_ioctl(struct usb_cdev *cdev, u_long cmd, caddr_t addr, int32_t fflags, struct thread *td); static void utouch_put_queue(struct utouch_softc *sc, int32_t dx, int32_t dy, int32_t dz, int32_t buttons); static int utouch_probe(device_t dev) { struct usb_attach_arg *uaa = device_get_ivars(dev); const struct utouch_product *up = utouch_products; usb_interface_descriptor_t *id; void *d_ptr; int32_t error = 0; #if (__FreeBSD_version >= 700000) int16_t d_len; #else int32_t d_len; #endif if (uaa->iface == NULL) { return UMATCH_NONE; } /* probe list of known products */ while (up->vendor) { if ((up->vendor == uaa->vendor) && (up->product == uaa->product)) { return UMATCH_VENDOR_PRODUCT; /* bid high */ } ++up; } id = usbd_get_interface_descriptor(uaa->iface); if ((id == NULL) || (id->bInterfaceClass != UICLASS_HID)) { return UMATCH_NONE; } #if (__FreeBSD_version >= 700000) error = hid_read_report_desc_from_usb(uaa->device, &usb_global_lock, &d_ptr, &d_len, M_TEMP, uaa->iface_index); #else error = usbreq_read_report_desc(uaa->device, uaa->iface_index, &d_ptr, &d_len, M_TEMP); #endif if (error) { return UMATCH_NONE; } /* interface class is HID, check if it belongs to us */ /* * /usr/share/misc/usb_hid_usages * 01 Generic Desktop * 0x02 Mouse * 0x30 X * 0x31 Y * 0x32 Z * 13 Digitizer * 0x04 Touch Screen */ if (hid_is_collection(d_ptr, d_len, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_POINTER)) || hid_is_collection(d_ptr, d_len, HID_USAGE2(HUP_DIGITIZERS, HUD_TOUCHSCREEN))) { /* generic pointing device or touchscreen - signal matching generic interface */ error = UMATCH_IFACECLASS_IFACESUBCLASS; } else { error = UMATCH_NONE; } free(d_ptr, M_TEMP); return error; } static int utouch_attach(device_t dev) { struct usb_attach_arg *uaa = device_get_ivars(dev); struct utouch_softc *sc = device_get_softc(dev); const struct utouch_product *up = utouch_products; usb_interface_descriptor_t *id; void *d_ptr = NULL; const char * p_buf[2]; int32_t unit = device_get_unit(dev); int32_t isize = 0; u_int32_t flags; int32_t err; u_int8_t i; char buf_1[16]; #if (__FreeBSD_version >= 700000) int16_t d_len; #else int32_t d_len; #endif #if (__FreeBSD_version >= 700000) usbd_set_device_desc(dev); #else usbd_set_desc(dev, uaa->device); #endif mtx_init(&(sc->sc_mtx), "utouch lock", NULL, MTX_DEF|MTX_RECURSE); #if (__FreeBSD_version >= 700000) usb_callout_init_mtx( #else __callout_init_mtx( #endif &(sc->sc_callout), &(sc->sc_mtx), CALLOUT_RETURNUNLOCKED); while (up->vendor) { if ((up->vendor == uaa->vendor) && (up->product == uaa->product)) { sc->sc_flags = up->flags; sc->decoder = NULL; switch (up->flags & UTF_MSK_TYPE) { case UTF_IS_EGSAW: sc->decoder = (touchdecode_t*)&decode_alphatouch; break; case UTF_IS_TSHARK: sc->decoder = (touchdecode_t*)&decode_tshark; break; case UTF_IS_DTC: sc->decoder = (touchdecode_t*)&decode_dtc; break; case UTF_IS_3MTOUCH: sc->decoder = (touchdecode_t*)&decode_3mmut_ex; break; default: device_printf(dev, "unknown decoder\n"); sc->decoder = NULL; break; } device_printf(dev, "$Rev: 2129 $ vendor 0x%04x product 0x%04x " "flags 0x%04x\n", uaa->vendor, uaa->product, up->flags); break; } ++up; } if (!up->vendor) { /* no product specific entry found */ id = usbd_get_interface_descriptor(uaa->iface); if ((id != NULL) && (id->bInterfaceClass == UICLASS_HID)) { device_printf(dev, "$Rev: 2129 $ attaching generic HID\n"); sc->sc_flags |= UTF_ISHID; } else { /* don't know about this device - how did we get here? */ device_printf(dev, "not a known device, not a generic HID\n"); goto detach; } } #if (__FreeBSD_version >= 700000) err = usbd_transfer_setup(uaa->device, &(uaa->iface_index), sc->sc_xfer, utouch_config, UT_N_TRANSFER, sc, &(sc->sc_mtx)); #else err = usbd_transfer_setup(uaa->device, uaa->iface_index, sc->sc_xfer, utouch_config, UT_N_TRANSFER, sc, &(sc->sc_mtx)); #endif if (err) { device_printf(dev, "usb error=%s\n", usbd_errstr(err)) ; goto detach; } if (UT_IS_HID(sc->sc_flags)) { #if (__FreeBSD_version >= 700000) err = hid_read_report_desc_from_usb(uaa->device, &usb_global_lock, &d_ptr, &d_len, M_TEMP, uaa->iface_index); #else err = usbreq_read_report_desc(uaa->device, uaa->iface_index, &d_ptr, &d_len, M_TEMP); #endif if (err) { device_printf(dev, "error reading report description\n"); goto detach; } #ifdef UTOUCH_DEBUG if (UTOUCH_DEBUG & 2) { /* debug only, print out report packet in hex */ DPRINTF(2, "HID report:\n"); for (i=0; isc_loc_x, &flags)) { sc->sc_flags |= UTF_X_AXIS; } if (hid_locate(d_ptr, d_len, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y), hid_input, &sc->sc_loc_y, &flags)) { sc->sc_flags |= UTF_Y_AXIS; } /* try to guess the Z activator: first check Z, then WHEEL */ if (hid_locate(d_ptr, d_len, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Z), hid_input, &sc->sc_loc_z, &flags)) { sc->sc_flags |= UTF_Z_AXIS; if (sc->sc_flags & UTF_ZUSAGEBROKEN) { device_printf(dev, "device reports Z axis (not broken)\n"); } } /* check for FLAGS - enable workaround by product-flags */ if (!(sc->sc_flags & UTF_Z_AXIS) && (sc->sc_flags & UTF_ZUSAGEBROKEN)) { if (hid_locate(d_ptr, d_len, HID_USAGE2(HUP_GENERIC_DESKTOP, _UT_HUG_PRESSURE), hid_input, &sc->sc_loc_z, &flags)) { device_printf(dev,"broken Z usage fixed\n"); sc->sc_flags |= UTF_Z_AXIS; } } /* figure out the number of buttons */ /* 2do: we have really ZERO buttons - emulate left button click for pressure */ for (i = 0; i < UT_BUTTON_MAX; i++) { if (!hid_locate(d_ptr, d_len, HID_USAGE2(HUP_BUTTON, (i+1)), hid_input, &(sc->sc_loc_btn[i]), NULL)) { break; } } sc->sc_buttons = i; isize = hid_report_size(d_ptr, d_len, hid_input, &sc->sc_iid); #if (__FreeBSD_version >= 700000) if (isize > sc->sc_xfer[0]->max_frame_size) { device_printf(dev, "WARNING: report size, %d bytes, is larger " "than interrupt size, %d bytes! blame the vendor!\n", isize, sc->sc_xfer[0]->max_frame_size); #else if (isize > sc->sc_xfer[0]->length) { device_printf(dev, "WARNING: report size, %d bytes, is larger " "than interrupt size, %d bytes! blame the vendor!\n", isize, sc->sc_xfer[0]->length); #endif } } else { /* not a HID */ sc->sc_buttons = 1; sc->sc_flags |= UTF_X_AXIS | UTF_Y_AXIS | UTF_POSABS; } device_printf(dev, "%d buttons and [%s%s%s] coordinates\n", (sc->sc_buttons), (sc->sc_flags & UTF_X_AXIS) ? "X" : "", (sc->sc_flags & UTF_Y_AXIS) ? "Y" : "", (sc->sc_flags & UTF_Z_AXIS) ? "Z" : ""); #ifdef UTOUCH_DEBUG if(UT_IS_HID(sc->sc_flags)) { DPRINTF(2, "sc=%p size=%d, id=%d\n", sc, isize, sc->sc_iid); DPRINTF(1, "X\t%d/%d\n", sc->sc_loc_x.pos, sc->sc_loc_x.size); DPRINTF(1, "Y\t%d/%d\n", sc->sc_loc_y.pos, sc->sc_loc_y.size); DPRINTF(1, "Z\t%d/%d\n", sc->sc_loc_z.pos, sc->sc_loc_z.size); for (i = 0; i < sc->sc_buttons; i++) { DPRINTF(4, "B%d\t%d/%d\n", i+1, sc->sc_loc_btn[i].pos, sc->sc_loc_btn[i].size); } } #endif /* init status flags + pos */ sc->sc_touch.poscurr.x = sc->sc_touch.poscurr.y = 0; sc->sc_touch.poslast.x = sc->sc_touch.poslast.y = 0; sc->sc_touch.posmin.x = sc->sc_touch.posmin.y = 0xffff; sc->sc_touch.posmax.x = sc->sc_touch.posmax.y = 0; sc->sc_touch.poscurr.pressure = sc->sc_touch.poslast.pressure = 0; snprintf(buf_1, sizeof(buf_1), "utouch%d", unit); p_buf[0] = buf_1; p_buf[1] = NULL; sc->sc_cdev.sc_start_read = &utouch_start_read; sc->sc_cdev.sc_stop_read = &utouch_stop_read; sc->sc_cdev.sc_open = &utouch_open; sc->sc_cdev.sc_ioctl = &utouch_ioctl; #if (__FreeBSD_version >= 700000) sc->sc_cdev.sc_flags |= (USB_CDEV_FLAG_WAKEUP_RD_IMMED | USB_CDEV_FLAG_WAKEUP_WR_IMMED); #else sc->sc_cdev.sc_flags |= (USB_CDEV_FLAG_FWD_SHORT| USB_CDEV_FLAG_WAKEUP_RD_IMMED|USB_CDEV_FLAG_WAKEUP_WR_IMMED); #endif err = usb_cdev_attach(&(sc->sc_cdev), sc, &(sc->sc_mtx), p_buf, UID_ROOT, GID_OPERATOR, 0666, UT_BUF_SIZE, UT_IFQ_MAXLEN, 1, 1 /* dummy write buffer */); if(d_ptr) { free(d_ptr, M_TEMP); d_ptr = NULL; } if (err) { goto detach; } return 0; detach: if (d_ptr) { free(d_ptr, M_TEMP); d_ptr = NULL; } utouch_detach(dev); return ENOMEM; } static int utouch_detach(device_t self) { struct utouch_softc *sc = device_get_softc(self); DPRINTF(2, "sc=%p\n", sc); usb_cdev_detach(&(sc->sc_cdev)); usbd_transfer_unsetup(sc->sc_xfer, UT_N_TRANSFER); #if (__FreeBSD_version >= 700000) usb_callout_drain(&(sc->sc_callout)); #else __callout_drain(&(sc->sc_callout)); #endif mtx_destroy(&(sc->sc_mtx)); return 0; } static void utouch_start_read(struct usb_cdev *cdev) { struct utouch_softc *sc = cdev->sc_priv_ptr; usbd_transfer_start(sc->sc_xfer[0]); return; } static void utouch_stop_read(struct usb_cdev *cdev) { struct utouch_softc *sc = cdev->sc_priv_ptr; usbd_transfer_stop(sc->sc_xfer[1]); usbd_transfer_stop(sc->sc_xfer[0]); #if (__FreeBSD_version >= 700000) usb_callout_stop(&(sc->sc_callout)); #else __callout_stop(&(sc->sc_callout)); #endif return; } static void utouch_put_queue(struct utouch_softc *sc, int32_t dx, int32_t dy, int32_t dz, int32_t buttons) { static utouch_proto_t clientproto; mtx_lock(&(sc->sc_mtx)); sc->sc_touch.poslast.x = sc->sc_touch.poscurr.x; sc->sc_touch.poslast.y = sc->sc_touch.poscurr.y; sc->sc_touch.poslast.pressure = sc->sc_touch.poscurr.pressure; /* current position */ sc->sc_touch.poscurr.x = dx; sc->sc_touch.poscurr.y = dy; sc->sc_touch.poscurr.pressure = dz; sc->sc_touch.buttons = buttons; /* 2do: this should make it to the calibration mode */ /* gather min / max coordinates */ sc->sc_touch.posmin.x = (sc->sc_touch.posmin.x > sc->sc_touch.poscurr.x) ? sc->sc_touch.poscurr.x : sc->sc_touch.posmin.x; sc->sc_touch.posmin.y = (sc->sc_touch.posmin.y > sc->sc_touch.poscurr.y) ? sc->sc_touch.poscurr.y : sc->sc_touch.posmin.y; sc->sc_touch.posmax.x = (sc->sc_touch.posmax.x < sc->sc_touch.poscurr.x) ? sc->sc_touch.poscurr.x : sc->sc_touch.posmax.x; sc->sc_touch.posmax.y = (sc->sc_touch.posmax.y < sc->sc_touch.poscurr.y) ? sc->sc_touch.poscurr.y : sc->sc_touch.posmax.y; sc->sc_touch.posmax.pressure = (sc->sc_touch.posmax.pressure < sc->sc_touch.poscurr.pressure && sc->sc_touch.poscurr.pressure < 255) ? sc->sc_touch.poscurr.pressure : sc->sc_touch.posmax.pressure; /* assemble client protocol packet */ clientproto.sig[0] = _UT_SIGNATURE1; clientproto.sig[1] = _UT_SIGNATURE2; clientproto.version = _UT_VERSION; clientproto.ssize = sizeof(utouch_proto_t); clientproto.mode = _UT_ABSOLUTE; memcpy( &clientproto.coord, &sc->sc_touch.poscurr, sizeof(utouch_coord_t)); clientproto.buttons = sc->sc_touch.buttons; if (clientproto.buttons == 0) clientproto.coord.pressure = 0; clientproto.res[0] = 0; #if (__FreeBSD_version >= 700000) usb_cdev_put_data_linear(&(sc->sc_cdev), &(clientproto), sizeof(utouch_proto_t), 1); #else usb_cdev_put_data(&(sc->sc_cdev), (u_int8_t*)&(clientproto), sizeof(utouch_proto_t), 0); #endif #ifdef UTOUCH_DEBUG DPRINTF(4, "min x: %04x y: %04x max x: %04x y: %04x\t%04x/%04x:%x\n", sc->sc_touch.posmin.x, sc->sc_touch.posmin.y, sc->sc_touch.posmax.x, sc->sc_touch.posmax.y, sc->sc_touch.poscurr.x, sc->sc_touch.poscurr.y, sc->sc_touch.poscurr.pressure); #endif mtx_unlock(&(sc->sc_mtx)); return; } /*static void utouch_reset_buf(struct utouch_softc *sc) { struct usbd_mbuf *m; /* reset read queue */ while(1) { USBD_IF_DEQUEUE(&(sc->sc_cdev.sc_rdq_used), m); if (m) { USBD_IF_ENQUEUE(&(sc->sc_cdev.sc_rdq_free), m); } else { break; } } return; } */ static int32_t utouch_open(struct usb_cdev *cdev, int32_t fflags, int32_t devtype, struct thread *td) { struct utouch_softc *sc = cdev->sc_priv_ptr; /* reset status */ /* sc->sc_status.flags = 0;*/ sc->sc_touch.buttons = 0; sc->sc_touch.poscurr.x = 0; sc->sc_touch.poscurr.y = 0; sc->sc_touch.poscurr.pressure = 0; sc->sc_touch.poslast.x = 0; sc->sc_touch.poslast.y = 0; sc->sc_touch.poslast.pressure = 0; return 0; } /* * top half driver */ static int32_t utouch_ioctl(struct usb_cdev *cdev, u_long cmd, caddr_t addr, int32_t fflags, struct thread *td) { struct utouch_softc *sc = cdev->sc_priv_ptr; int error = 0; mtx_lock(&(sc->sc_mtx)); switch(cmd) { case TOUCH_GETSTATUS: { /* utouch_status_t *status = (utouch_status_t*) addr;*/ /* status->poscurr = sc->sc_touch.poscurr;*/ memcpy( addr, &sc->sc_touch, sizeof( utouch_status_t ) ); break; } case TOUCH_GETPOSITION: { utouch_coord_t *coord = (utouch_coord_t*) addr; coord->x = sc->sc_touch.poscurr.x; coord->y = sc->sc_touch.poscurr.y; coord->pressure = sc->sc_touch.poscurr.pressure; break; } /* case TOUCH_CALIBRATE: break; */ case F_SETOWN: /* do nothing */ break; default: error = ENOTTY; } mtx_unlock(&(sc->sc_mtx)); return error; } /* static void utouch_put_queue_timeout(void *__sc) { struct utouch_softc *sc = __sc; mtx_assert(&(sc->sc_mtx), MA_OWNED); utouch_put_queue(sc, 0, 0, 0, 0, 0); mtx_unlock(&(sc->sc_mtx)); return; } */ static void utouch_clear_stall_callback(struct usbd_xfer *xfer) { struct utouch_softc *sc = xfer->priv_sc; #if (__FreeBSD_version >= 700000) struct usbd_xfer *xfer_other = sc->sc_xfer[0]; if (usbd_clear_stall_callback(xfer, xfer_other)) { sc->sc_flags &= ~UTF_INTR_STALL; usbd_transfer_start(xfer_other); DPRINTF(16, "stall cleared\n"); } #else USBD_CHECK_STATUS(xfer); tr_setup: /* start clear stall */ usbd_clear_stall_tr_setup(xfer, sc->sc_xfer[0]); return; tr_transferred: usbd_clear_stall_tr_transferred(xfer, sc->sc_xfer[0]); sc->sc_flags &= ~UTF_INTR_STALL; usbd_transfer_start(sc->sc_xfer[0]); return; tr_error: /* bomb out */ sc->sc_flags &= ~UTF_INTR_STALL; DPRINTF(16, "clear stall failed, error=%s\n", usbd_errstr(xfer->error)); return; } #endif } /* * utouch_intr_callback * driver bottom half - code with caution! */ static void utouch_intr_callback(struct usbd_xfer *xfer) { struct utouch_softc *sc = xfer->priv_sc; struct usbd_mbuf *m; #if (__FreeBSD_version >= 700000) u_int8_t *buf = xfer->local_buffer; #else u_int8_t *buf = xfer->buffer; #endif u_int16_t len = xfer->actlen; static int32_t buttons; static int32_t dx = 0; static int32_t dy = 0; static int32_t dz = 0; static u_int8_t i; static u_int8_t filterthis; utouch_coord_t ddd; buttons = dx = dy = dz = 0; filterthis = 0; #if (__FreeBSD_version >= 700000) switch( USBD_GET_STATE(xfer) ) { #else USBD_CHECK_STATUS(xfer) #endif #if (__FreeBSD_version >= 700000) case USBD_ST_TRANSFERRED: #else tr_transferred: #endif #ifdef UTOUCH_DEBUG DPRINTF(128, "sc=%p actlen=%d data = " "%02x %02x %02x %02x %02x %02x %02x %02x\n", sc, len, (len > 0) ? buf[0] : 0, (len > 1) ? buf[1] : 0, (len > 2) ? buf[2] : 0, (len > 3) ? buf[3] : 0, (len > 4) ? buf[4] : 0, (len > 5) ? buf[5] : 0, (len > 6) ? buf[6] : 0, (len > 7) ? buf[7] : 0); #endif if(UT_IS_HID(sc->sc_flags)) { dx = (sc->sc_flags & UTF_X_AXIS) ? hid_get_data(buf, len, &sc->sc_loc_x) : 0; dy = (sc->sc_flags & UTF_Y_AXIS) ? hid_get_data(buf, len, &sc->sc_loc_y) : 0; dz = (sc->sc_flags & UTF_Z_AXIS) ? hid_get_data(buf, len, &sc->sc_loc_z) : 0; if(sc->sc_flags & UTF_ZCLIP && dz == _UT_ZCLIP_VAL) { /* * device tries to signal a clipping Z value * too much pressure, too much fingers on touchscreen */ dz = _UT_ZCLIP_FIX; } for (i = 0; i < sc->sc_buttons; i++) { if (hid_get_data(buf, len, &sc->sc_loc_btn[i])) { buttons |= (1 << UT_BUT(i)); } } } if (sc->decoder != NULL) { if ( sc->decoder(buf, &ddd)) { /* decoder signals error */ return; } dx = ddd.x; dy = ddd.y; dz = ddd.pressure; if (ddd.pressure) buttons = 1; else buttons = 0; } if (dx || dy || dz || (buttons != sc->sc_touch.buttons)) { #ifdef UTOUCH_DEBUG DPRINTF(64, "x:%04x y:%04x z:%u buttons:0x%08x\n", dx, dy, dz, buttons); #endif if(sc->sc_touch.buttons == buttons && (buttons & 1) == 0) { /* * device reports untouched device but we haven't had * a touch before - trash this packet */ filterthis = 1; DPRINTF(32,"phantom click detected!\n"); } mtx_lock(&(sc->sc_mtx)); if( !filterthis ) { sc->sc_touch.buttons = buttons; sc->sc_touch.poscurr.x = dx; sc->sc_touch.poscurr.y = dy; sc->sc_touch.poscurr.pressure = dz; } #if (__FreeBSD_version >= 700000) usb_callout_stop(&(sc->sc_callout)); #else __callout_stop(&(sc->sc_callout)); #endif mtx_unlock(&(sc->sc_mtx)); if(!filterthis) { utouch_put_queue(sc, dx, dy, dz, buttons); } } #if (__FreeBSD_version >= 700000) case USBD_ST_SETUP: #else tr_setup: #endif if (sc->sc_flags & UTF_INTR_STALL) { usbd_transfer_start(sc->sc_xfer[1]); } else { USBD_IF_POLL(&(sc->sc_cdev.sc_rdq_free), m); if (m) { #if (__FreeBSD_version >= 700000) xfer->frlengths[0] = xfer->max_data_length; #endif usbd_start_hardware(xfer); } } return; #if (__FreeBSD_version >= 700000) case USBD_ST_ERROR: default: #else tr_error: #endif if (xfer->error != USBD_ERR_CANCELLED) { /* start clear stall */ sc->sc_flags |= UTF_INTR_STALL; usbd_transfer_start(sc->sc_xfer[1]); DPRINTF(32,"device polling activated\n"); } return; #if (__FreeBSD_version >= 700000) } #endif } static const struct usbd_config utouch_config[UT_N_TRANSFER] = { [0] = { .type = UE_INTERRUPT, .endpoint = UE_ADDR_ANY, /*-1,*/ /* any */ .direction = UE_DIR_IN, #if (__FreeBSD_version >= 700000) .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, .mh.bufsize = 0, .mh.callback = &utouch_intr_callback, #else .flags = USBD_SHORT_XFER_OK, .bufsize = 0, /* use wMaxPacketSize */ .callback = &utouch_intr_callback, #endif }, [1] = { .type = UE_CONTROL, .endpoint = 0x00, /* Control pipe */ .direction = UE_DIR_ANY, /* -1, */ #if (__FreeBSD_version >= 700000) .mh.bufsize = sizeof(usb_device_request_t), .mh.callback = &utouch_clear_stall_callback, .mh.timeout = 1000, #else .bufsize = sizeof(usb_device_request_t), .callback = &utouch_clear_stall_callback, .timeout = 1000, /* 1 second */ #endif }, }; static devclass_t utouch_devclass; static device_method_t utouch_methods[] = { DEVMETHOD(device_probe, utouch_probe), DEVMETHOD(device_attach, utouch_attach), DEVMETHOD(device_detach, utouch_detach), { 0, 0 } }; static driver_t utouch_driver = { .name = "utouch", .methods = utouch_methods, .size = sizeof(struct utouch_softc), }; DRIVER_MODULE(utouch, uhub, utouch_driver, utouch_devclass, usbd_driver_load, 0); MODULE_DEPEND(utouch, usb, 1, 1, 1); /*MODULE_DEPEND(utouch, uhid, 1, 1, 1);*/