Author: glebius
Date: Tue May 25 21:20:56 2010
New Revision: 208554
URL: http://svn.freebsd.org/changeset/base/208554

Log:
  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.

Added:
  head/share/man/man4/uep.4   (contents, props changed)
  head/sys/dev/usb/input/uep.c   (contents, props changed)
  head/sys/modules/usb/uep/
  head/sys/modules/usb/uep/Makefile   (contents, props changed)
Modified:
  head/share/man/man4/Makefile
  head/sys/conf/NOTES
  head/sys/conf/files
  head/sys/dev/usb/usbdevs

Modified: head/share/man/man4/Makefile
==============================================================================
--- head/share/man/man4/Makefile        Tue May 25 20:42:35 2010        
(r208553)
+++ head/share/man/man4/Makefile        Tue May 25 21:20:56 2010        
(r208554)
@@ -435,6 +435,7 @@ MAN=        aac.4 \
        udav.4 \
        udbp.4 \
        udp.4 \
+       uep.4 \
        ufm.4 \
        ufoma.4 \
        uftdi.4 \

Added: head/share/man/man4/uep.4
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/share/man/man4/uep.4   Tue May 25 21:20:56 2010        (r208554)
@@ -0,0 +1,79 @@
+.\" Copyright (c) 2010 Gleb Smirnoff <gleb...@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 gleb...@freebsd.org

Modified: head/sys/conf/NOTES
==============================================================================
--- head/sys/conf/NOTES Tue May 25 20:42:35 2010        (r208553)
+++ head/sys/conf/NOTES Tue May 25 21:20:56 2010        (r208554)
@@ -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
 #

Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files Tue May 25 20:42:35 2010        (r208553)
+++ head/sys/conf/files Tue May 25 21:20:56 2010        (r208554)
@@ -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

Added: head/sys/dev/usb/input/uep.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/sys/dev/usb/input/uep.c        Tue May 25 21:20:56 2010        
(r208554)
@@ -0,0 +1,441 @@
+/*-
+ * Copyright 2010, Gleb Smirnoff <gleb...@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);

Modified: head/sys/dev/usb/usbdevs
==============================================================================
--- head/sys/dev/usb/usbdevs    Tue May 25 20:42:35 2010        (r208553)
+++ head/sys/dev/usb/usbdevs    Tue May 25 21:20:56 2010        (r208554)
@@ -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
 

Added: head/sys/modules/usb/uep/Makefile
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/sys/modules/usb/uep/Makefile   Tue May 25 21:20:56 2010        
(r208554)
@@ -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>
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to