diff options
-rw-r--r-- | share/man/man4/Makefile | 1 | ||||
-rw-r--r-- | share/man/man4/uep.4 | 79 | ||||
-rw-r--r-- | sys/conf/NOTES | 2 | ||||
-rw-r--r-- | sys/conf/files | 1 | ||||
-rw-r--r-- | sys/dev/usb/input/uep.c | 441 | ||||
-rw-r--r-- | sys/dev/usb/usbdevs | 5 | ||||
-rw-r--r-- | sys/modules/usb/uep/Makefile | 11 |
7 files changed, 540 insertions, 0 deletions
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile index b1282da..014be50 100644 --- a/share/man/man4/Makefile +++ b/share/man/man4/Makefile @@ -435,6 +435,7 @@ MAN= aac.4 \ udav.4 \ udbp.4 \ udp.4 \ + uep.4 \ ufm.4 \ ufoma.4 \ uftdi.4 \ diff --git a/share/man/man4/uep.4 b/share/man/man4/uep.4 new file mode 100644 index 0000000..d89805e --- /dev/null +++ b/share/man/man4/uep.4 @@ -0,0 +1,79 @@ +.\" Copyright (c) 2010 Gleb Smirnoff <glebius@FreeBSD.org> +.\" 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. +.\" +.\" $FreeBSD$ +.\" +.Dd May 25, 2010 +.Dt UEP 4 +.Os +.Sh NAME +.Nm uep +.Nd eGalax touchscreen driver +.Sh SYNOPSIS +To compile this driver into the kernel, place the following lines into +your kernel configuration file: +.Bd -ragged -offset indent +.Cd "device uep" +.Cd "device usb" +.Ed +.Pp +Alternatively, to load the driver as a +module at boot time, place the following line in +.Xr loader.conf 5 : +.Bd -literal -offset indent +uep_load="YES" +.Ed +.Sh DESCRIPTION +The +.Nm +driver provides support for the eGalax onscreen touch panels. +.Pp +The driver is stub. +It just probes and attaches to USB device, creates device entry +and feeds reassambled packets from the hardware to it. +.Pp +To get mouse working in +.Xr X 7 , +one needs to install +.Pa ports/x11-drivers/xf86-input-egalax . +.Sh BUGS +.Nm +can't act like +.Xr sysmouse 4 , +since the latter does not support absolute motion events. +.Sh FILES +.Nm +creates a blocking pseudo\-device file, +.Pa /dev/uep0 . +.Sh SEE ALSO +.Xr usb 4 , +.Xr loader.conf 5 , +.Xr xorg.conf 5 Pq Pa ports/x11/xorg , +.Xr egalax 4 Pq Pa ports/x11-drivers/xf86-input-egalax . +.Sh AUTHORS +.An -nosplit +The +.Nm +driver was written by +.An Gleb Smirnoff Aq glebius@FreeBSD.org diff --git a/sys/conf/NOTES b/sys/conf/NOTES index 1ec82a9..6d12f99 100644 --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -2627,6 +2627,8 @@ device umct device umodem # USB mouse device ums +# eGalax USB touch screen +device uep # Diamond Rio 500 MP3 player device urio # diff --git a/sys/conf/files b/sys/conf/files index 23fab8c..12f5e4d 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1781,6 +1781,7 @@ dev/usb/misc/udbp.c optional udbp # USB input drivers # dev/usb/input/atp.c optional atp +dev/usb/input/uep.c optional uep dev/usb/input/uhid.c optional uhid dev/usb/input/ukbd.c optional ukbd dev/usb/input/ums.c optional ums diff --git a/sys/dev/usb/input/uep.c b/sys/dev/usb/input/uep.c new file mode 100644 index 0000000..27dec1f --- /dev/null +++ b/sys/dev/usb/input/uep.c @@ -0,0 +1,441 @@ +/*- + * Copyright 2010, Gleb Smirnoff <glebius@FreeBSD.org> + * 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. + * + * $FreeBSD$ + */ + +/* + * http://home.eeti.com.tw/web20/drivers/Software%20Programming%20Guide_v2.0.pdf + */ + +#include <sys/param.h> +#include <sys/bus.h> +#include <sys/callout.h> +#include <sys/conf.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/module.h> +#include <sys/mutex.h> +#include <sys/sysctl.h> +#include <sys/systm.h> + +#include <dev/usb/usb.h> +#include <dev/usb/usbdi.h> +#include <dev/usb/usbdi_util.h> +#include <dev/usb/usbhid.h> +#include "usbdevs.h" + +#include <sys/ioccom.h> +#include <sys/fcntl.h> +#include <sys/tty.h> + +#define USB_DEBUG_VAR uep_debug +#include <dev/usb/usb_debug.h> + +#ifdef USB_DEBUG +static int uep_debug = 0; + +SYSCTL_NODE(_hw_usb, OID_AUTO, uep, CTLFLAG_RW, 0, "USB uep"); +SYSCTL_INT(_hw_usb_uep, OID_AUTO, debug, CTLFLAG_RW, + &uep_debug, 0, "Debug level"); +#endif + +#define UEP_MAX_X 2047 +#define UEP_MAX_Y 2047 + +#define UEP_DOWN 0x01 +#define UEP_PACKET_LEN_MAX 16 +#define UEP_PACKET_LEN_REPORT 5 +#define UEP_PACKET_LEN_REPORT2 6 +#define UEP_PACKET_DIAG 0x0a +#define UEP_PACKET_REPORT_MASK 0xe0 +#define UEP_PACKET_REPORT 0x80 +#define UEP_PACKET_REPORT_PRESSURE 0xc0 +#define UEP_PACKET_REPORT_PLAYER 0xa0 +#define UEP_PACKET_LEN_MASK + +#define UEP_FIFO_BUF_SIZE 8 /* bytes */ +#define UEP_FIFO_QUEUE_MAXLEN 50 /* units */ + +enum { + UEP_INTR_DT, + UEP_N_TRANSFER, +}; + +struct uep_softc { + struct mtx mtx; + + struct usb_xfer *xfer[UEP_N_TRANSFER]; + struct usb_fifo_sc fifo; + + u_int pollrate; + u_int state; +#define UEP_ENABLED 0x01 + + /* Reassembling buffer. */ + u_char buf[UEP_PACKET_LEN_MAX]; + uint8_t buf_len; +}; + +static usb_callback_t uep_intr_callback; + +static device_probe_t uep_probe; +static device_attach_t uep_attach; +static device_detach_t uep_detach; + +static usb_fifo_cmd_t uep_start_read; +static usb_fifo_cmd_t uep_stop_read; +static usb_fifo_open_t uep_open; +static usb_fifo_close_t uep_close; + +static void uep_put_queue(struct uep_softc *, u_char *); + +static struct usb_fifo_methods uep_fifo_methods = { + .f_open = &uep_open, + .f_close = &uep_close, + .f_start_read = &uep_start_read, + .f_stop_read = &uep_stop_read, + .basename[0] = "uep", +}; + +static int +get_pkt_len(u_char *buf) +{ + if (buf[0] == UEP_PACKET_DIAG) { + int len; + + len = buf[1] + 2; + if (len > UEP_PACKET_LEN_MAX) { + DPRINTF("bad packet len %u\n", len); + return (UEP_PACKET_LEN_MAX); + } + + return (len); + } + + switch (buf[0] & UEP_PACKET_REPORT_MASK) { + case UEP_PACKET_REPORT: + return (UEP_PACKET_LEN_REPORT); + case UEP_PACKET_REPORT_PRESSURE: + case UEP_PACKET_REPORT_PLAYER: + case UEP_PACKET_REPORT_PRESSURE | UEP_PACKET_REPORT_PLAYER: + return (UEP_PACKET_LEN_REPORT2); + default: + DPRINTF("bad packet len 0\n"); + return (0); + } +} + +static void +uep_process_pkt(struct uep_softc *sc, u_char *buf) +{ + int32_t x, y; + + if ((buf[0] & 0xFE) != 0x80) { + DPRINTF("bad input packet format 0x%.2x\n", buf[0]); + return; + } + + /* + * Packet format is 5 bytes: + * + * 1000000T + * 0000AAAA + * 0AAAAAAA + * 0000BBBB + * 0BBBBBBB + * + * T: 1=touched 0=not touched + * A: bits of axis A position, MSB to LSB + * B: bits of axis B position, MSB to LSB + * + * For the unit I have, which is CTF1020-S from CarTFT.com, + * A = X and B = Y. But in NetBSD uep(4) it is other way round :) + * + * The controller sends a stream of T=1 events while the + * panel is touched, followed by a single T=0 event. + * + */ + + x = (buf[1] << 7) | buf[2]; + y = (buf[3] << 7) | buf[4]; + + DPRINTFN(2, "x %u y %u\n", x, y); + + uep_put_queue(sc, buf); +} + +static void +uep_intr_callback(struct usb_xfer *xfer, usb_error_t error) +{ + struct uep_softc *sc = usbd_xfer_softc(xfer); + int len; + + usbd_xfer_status(xfer, &len, NULL, NULL, NULL); + + switch (USB_GET_STATE(xfer)) { + case USB_ST_TRANSFERRED: + { + struct usb_page_cache *pc; + u_char buf[17], *p; + int pkt_len; + + if (len > sizeof(buf)) { + DPRINTF("bad input length %d\n", len); + goto tr_setup; + } + + pc = usbd_xfer_get_frame(xfer, 0); + usbd_copy_out(pc, 0, buf, len); + + /* + * The below code mimics Linux a lot. I don't know + * why NetBSD reads complete packets, but we need + * to reassamble 'em like Linux does (tries?). + */ + if (sc->buf_len > 0) { + int res; + + if (sc->buf_len == 1) + sc->buf[1] = buf[0]; + + if ((pkt_len = get_pkt_len(sc->buf)) == 0) + goto tr_setup; + + res = pkt_len - sc->buf_len; + memcpy(sc->buf + sc->buf_len, buf, res); + uep_process_pkt(sc, sc->buf); + sc->buf_len = 0; + + p = buf + res; + len -= res; + } else + p = buf; + + if (len == 1) { + sc->buf[0] = buf[0]; + sc->buf_len = 1; + + goto tr_setup; + } + + while (len > 0) { + if ((pkt_len = get_pkt_len(p)) == 0) + goto tr_setup; + + /* full packet: process */ + if (pkt_len <= len) { + uep_process_pkt(sc, p); + } else { + /* incomplete packet: save in buffer */ + memcpy(sc->buf, p, len); + sc->buf_len = len; + } + p += pkt_len; + len -= pkt_len; + } + } + case USB_ST_SETUP: + tr_setup: + /* check if we can put more data into the FIFO */ + if (usb_fifo_put_bytes_max(sc->fifo.fp[USB_FIFO_RX]) != 0) { + usbd_xfer_set_frame_len(xfer, 0, + usbd_xfer_max_len(xfer)); + usbd_transfer_submit(xfer); + } + break; + + default: + if (error != USB_ERR_CANCELLED) { + /* try clear stall first */ + usbd_xfer_set_stall(xfer); + goto tr_setup; + } + break; + } +} + +static const struct usb_config uep_config[UEP_N_TRANSFER] = { + [UEP_INTR_DT] = { + .type = UE_INTERRUPT, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_IN, + .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, + .bufsize = 0, /* use wMaxPacketSize */ + .callback = &uep_intr_callback, + }, +}; + +static int +uep_probe(device_t dev) +{ + struct usb_attach_arg *uaa = device_get_ivars(dev); + + if (uaa->usb_mode != USB_MODE_HOST) + return (ENXIO); + + if ((uaa->info.idVendor == USB_VENDOR_EGALAX) && + ((uaa->info.idProduct == USB_PRODUCT_EGALAX_TPANEL) || + (uaa->info.idProduct == USB_PRODUCT_EGALAX_TPANEL2))) + return (BUS_PROBE_SPECIFIC); + + if ((uaa->info.idVendor == USB_VENDOR_EGALAX2) && + (uaa->info.idProduct == USB_PRODUCT_EGALAX2_TPANEL)) + return (BUS_PROBE_SPECIFIC); + + return (ENXIO); +} + +static int +uep_attach(device_t dev) +{ + struct usb_attach_arg *uaa = device_get_ivars(dev); + struct uep_softc *sc = device_get_softc(dev); + int error; + + device_set_usb_desc(dev); + + mtx_init(&sc->mtx, "uep lock", NULL, MTX_DEF); + + error = usbd_transfer_setup(uaa->device, &uaa->info.bIfaceIndex, + sc->xfer, uep_config, UEP_N_TRANSFER, sc, &sc->mtx); + + if (error) { + DPRINTF("usbd_transfer_setup error=%s\n", usbd_errstr(error)); + goto detach; + } + + error = usb_fifo_attach(uaa->device, sc, &sc->mtx, &uep_fifo_methods, + &sc->fifo, device_get_unit(dev), 0 - 1, uaa->info.bIfaceIndex, + UID_ROOT, GID_OPERATOR, 0644); + + if (error) { + DPRINTF("usb_fifo_attach error=%s\n", usbd_errstr(error)); + goto detach; + } + + sc->buf_len = 0; + + return (0); + +detach: + uep_detach(dev); + + return (ENOMEM); /* XXX */ +} + +static int +uep_detach(device_t dev) +{ + struct uep_softc *sc = device_get_softc(dev); + + usb_fifo_detach(&sc->fifo); + + usbd_transfer_unsetup(sc->xfer, UEP_N_TRANSFER); + + mtx_destroy(&sc->mtx); + + return (0); +} + +static void +uep_start_read(struct usb_fifo *fifo) +{ + struct uep_softc *sc = usb_fifo_softc(fifo); + u_int rate; + + if ((rate = sc->pollrate) > 1000) + rate = 1000; + + if (rate > 0 && sc->xfer[UEP_INTR_DT] != NULL) { + usbd_transfer_stop(sc->xfer[UEP_INTR_DT]); + usbd_xfer_set_interval(sc->xfer[UEP_INTR_DT], 1000 / rate); + sc->pollrate = 0; + } + + usbd_transfer_start(sc->xfer[UEP_INTR_DT]); +} + +static void +uep_stop_read(struct usb_fifo *fifo) +{ + struct uep_softc *sc = usb_fifo_softc(fifo); + + usbd_transfer_stop(sc->xfer[UEP_INTR_DT]); +} + +static void +uep_put_queue(struct uep_softc *sc, u_char *buf) +{ + usb_fifo_put_data_linear(sc->fifo.fp[USB_FIFO_RX], buf, + UEP_PACKET_LEN_REPORT, 1); +} + +static int +uep_open(struct usb_fifo *fifo, int fflags) +{ + if (fflags & FREAD) { + struct uep_softc *sc = usb_fifo_softc(fifo); + + if (sc->state & UEP_ENABLED) + return (EBUSY); + if (usb_fifo_alloc_buffer(fifo, UEP_FIFO_BUF_SIZE, + UEP_FIFO_QUEUE_MAXLEN)) + return (ENOMEM); + + sc->state |= UEP_ENABLED; + } + + return (0); +} + +static void +uep_close(struct usb_fifo *fifo, int fflags) +{ + if (fflags & FREAD) { + struct uep_softc *sc = usb_fifo_softc(fifo); + + sc->state &= ~(UEP_ENABLED); + usb_fifo_free_buffer(fifo); + } +} + +static devclass_t uep_devclass; + +static device_method_t uep_methods[] = { + DEVMETHOD(device_probe, uep_probe), + DEVMETHOD(device_attach, uep_attach), + DEVMETHOD(device_detach, uep_detach), + { 0, 0 }, +}; + +static driver_t uep_driver = { + .name = "uep", + .methods = uep_methods, + .size = sizeof(struct uep_softc), +}; + +DRIVER_MODULE(uep, uhub, uep_driver, uep_devclass, NULL, NULL); +MODULE_DEPEND(uep, usb, 1, 1, 1); diff --git a/sys/dev/usb/usbdevs b/sys/dev/usb/usbdevs index 3192e55..2322f6e 100644 --- a/sys/dev/usb/usbdevs +++ b/sys/dev/usb/usbdevs @@ -1378,6 +1378,11 @@ product EDIMAX RT2870_1 0x7711 RT2870 product EDIMAX EW7717 0x7717 EW-7717 product EDIMAX EW7718 0x7718 EW-7718 +/* eGalax Products */ +product EGALAX TPANEL 0x0001 Touch Panel +product EGALAX TPANEL2 0x0002 Touch Panel +product EGALAX2 TPANEL 0x0001 Touch Panel + /* Eicon Networks */ product EICON DIVA852 0x4905 Diva 852 ISDN TA diff --git a/sys/modules/usb/uep/Makefile b/sys/modules/usb/uep/Makefile new file mode 100644 index 0000000..4ffacde --- /dev/null +++ b/sys/modules/usb/uep/Makefile @@ -0,0 +1,11 @@ +# $FreeBSD$ + +S= ${.CURDIR}/../../.. + +.PATH: $S/dev/usb/input + +KMOD= uep +SRCS= opt_bus.h opt_usb.h device_if.h bus_if.h usb_if.h vnode_if.h usbdevs.h \ + uep.c + +.include <bsd.kmod.mk> |