summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorglebius <glebius@FreeBSD.org>2010-05-25 21:20:56 +0000
committerglebius <glebius@FreeBSD.org>2010-05-25 21:20:56 +0000
commit0cadc029c7db489deac27335e5d81f120d8c58a1 (patch)
treec338f9d6856307fdb33f189cc895abf0ee67333b
parentf6ab4a681092467819a08db78ce8d607027932f3 (diff)
downloadFreeBSD-src-0cadc029c7db489deac27335e5d81f120d8c58a1.zip
FreeBSD-src-0cadc029c7db489deac27335e5d81f120d8c58a1.tar.gz
Add uep(4), driver for USB onscreen touch panel from eGalax.
The driver is stub. It just creates device entry and feeds reassembled packets from hardware into it. If in future we would port wsmouse(4) from NetBSD, or make sysmouse(4) to support absolute motion events, then the driver can be extended to act as system mouse. Meanwhile, it just presents a /dev/uep0, that can be utilized by X driver, that I am going to commit to ports tree soon. The name for the driver is chosen to be the same as in NetBSD, however, due to different USB stacks this driver isn't a port.
-rw-r--r--share/man/man4/Makefile1
-rw-r--r--share/man/man4/uep.479
-rw-r--r--sys/conf/NOTES2
-rw-r--r--sys/conf/files1
-rw-r--r--sys/dev/usb/input/uep.c441
-rw-r--r--sys/dev/usb/usbdevs5
-rw-r--r--sys/modules/usb/uep/Makefile11
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>
OpenPOWER on IntegriCloud