tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: psaux driver



On Wednesday 08 June 2011 00:57:43 you wrote:
> I'm not sure if this is operationally equivalent to what you have, but
> it might be of some interest.

Hello,
I've read the code and it has some differences:
-what I export to userland has no prepreprocessing (I see that you filter out 
only full, proper synaptics packets)
-I have also added support for writing (which is directly translated into ps 
commands)

I think that (correct me if I'm wrong) your solution cannot be used for X11 
driver, because there would be 2 sources of ps commands - one from the X 
driver and one from the kernel synaptics driver.

Can I ask you, what are you using this driver for?

Anyway, I'll send a query to tech-x11, maybe they have some better ideas how 
to make use of the userspace X11 synaptics driver.

I attach the patch to be more specific

Regards

-- 
Marek Dopiera
marek%dopiera.pl@localhost
diff --git a/sys/arch/amd64/conf/majors.amd64 b/sys/arch/amd64/conf/majors.amd64
index f8f3a9a..719d4c3 100644
--- a/sys/arch/amd64/conf/majors.amd64
+++ b/sys/arch/amd64/conf/majors.amd64
@@ -90,6 +90,7 @@ device-major  kttcp           char 92                 kttcp
 device-major   dpt             char 96                 dpt
 device-major   twe             char 97                 twe
 device-major   nsmb            char 98                 nsmb            
+device-major   psaux   char 99                 psaux
 
 #
 # Device majors for Xen. These are assigned here so that:
diff --git a/sys/dev/pckbport/files.pckbport b/sys/dev/pckbport/files.pckbport
index b047ce5..7da8626 100644
--- a/sys/dev/pckbport/files.pckbport
+++ b/sys/dev/pckbport/files.pckbport
@@ -20,4 +20,7 @@ device        pms: wsmousedev
 attach pms at pckbport
 file   dev/pckbport/pms.c              pms
 file   dev/pckbport/synaptics.c        pms & pms_synaptics_touchpad
+device psaux
+attach psaux at pckbport
+file   dev/pckbport/psaux.c psaux
 file   dev/pckbport/elantech.c         pms & pms_elantech_touchpad
diff --git a/sys/dev/pckbport/psaux.c b/sys/dev/pckbport/psaux.c
new file mode 100644
index 0000000..95fa2e4
--- /dev/null
+++ b/sys/dev/pckbport/psaux.c
@@ -0,0 +1,412 @@
+/* $NetBSD: psaux.c,v 1.26 2008/03/15 18:59:07 cube Exp $ */
+
+/*-
+ * Copyright (c) 2010 Marek Dopiera
+ * Copyright (c) 2004 Kentaro Kurahone.
+ * Copyright (c) 2004 Ales Krenek.
+ * Copyright (c) 1994 Charles M. Hannum.
+ * Copyright (c) 1992, 1993 Erik Forsberg.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ``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 I 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.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: psaux.c,v 1.26 2008/03/15 18:59:07 cube Exp $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/select.h>
+#include <sys/device.h>
+#include <sys/ioctl.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/conf.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
+#include <sys/poll.h>
+#include <sys/vnode.h>
+
+#include <sys/bus.h>
+
+#include <dev/pckbport/pmsreg.h>
+#include <dev/pckbport/pckbportvar.h>
+//#define PSAUXDEBUG
+#ifdef PSAUXDEBUG
+static int const psaux_debug = 1;
+#else
+static int const psaux_debug = 0;
+#endif
+#define DPRINTF(...)    do { if (psaux_debug) printf(__VA_ARGS__); } while (0)
+
+#define RING_BUF_SIZE 64
+
+#define min(a,b) (((a) < (b)) ? (a):(b))
+
+struct ring_buffer {
+       unsigned char rb_buf[RING_BUF_SIZE];
+       size_t rb_start;
+       size_t rb_length;
+};
+
+struct psaux_softc {
+       device_t sc_dev;
+       pckbport_tag_t sc_kbctag;
+       int sc_kbcslot;
+       int sc_enabled;         /* input enabled? */
+       struct ring_buffer sc_rbuf;
+       struct selinfo sc_sel;
+       kmutex_t sc_lock;
+       kcondvar_t sc_cond;
+       int sc_closing;
+};
+
+static dev_type_open(psaux_open);
+static dev_type_close(psaux_close);
+static dev_type_read(psaux_read);
+static dev_type_write(psaux_write);
+static dev_type_poll(psaux_poll);
+static void rbuf_init(struct ring_buffer *);
+static size_t rbuf_drain(struct ring_buffer *, unsigned char *, size_t);
+static void rbuf_add(struct ring_buffer *, unsigned char);
+static __inline bool rbuf_empty(struct ring_buffer *);
+static int psaux_match(device_t, cfdata_t, void *);
+static void psaux_attach(device_t, device_t, void *);
+static void    do_enable(struct psaux_softc *);
+static void    do_disable(struct psaux_softc *);
+static int psaux_enable(void *);
+static void psaux_disable(void *);
+static bool    psaux_suspend(device_t PMF_FN_PROTO);
+static bool    psaux_resume(device_t PMF_FN_PROTO);
+static void psaux_input(void *, int);
+
+CFATTACH_DECL_NEW(psaux, sizeof (struct psaux_softc),
+    psaux_match, psaux_attach, NULL, NULL);
+extern struct cfdriver psaux_cd;
+
+const struct cdevsw psaux_cdevsw = {
+       psaux_open, psaux_close, psaux_read, psaux_write, noioctl,
+       nostop, notty, psaux_poll, nommap, nokqfilter, D_OTHER
+};
+
+static void
+rbuf_init(struct ring_buffer * rbuf)
+{
+       rbuf->rb_start = 0;
+       rbuf->rb_length = 0;
+}
+
+static size_t
+rbuf_drain(struct ring_buffer * rbuf, unsigned char * out_buf, size_t out_size)
+{
+       size_t to_copy, to_copy1;
+       to_copy = min(out_size, rbuf->rb_length);
+       to_copy1 = min(to_copy, RING_BUF_SIZE - rbuf->rb_start);
+       memcpy(out_buf, rbuf->rb_buf + rbuf->rb_start, to_copy1);
+       if (to_copy1 < to_copy)
+               memcpy(out_buf + to_copy1, rbuf->rb_buf, to_copy - to_copy1);
+       rbuf->rb_start = (rbuf->rb_start + to_copy) % RING_BUF_SIZE;
+       rbuf->rb_length -= to_copy;
+       return to_copy;
+}
+
+static void
+rbuf_add(struct ring_buffer * rbuf, unsigned char data)
+{
+       size_t pos = (rbuf->rb_start + rbuf->rb_length) % RING_BUF_SIZE;
+       if (rbuf->rb_length == RING_BUF_SIZE) {
+               DPRINTF(
+                       "psaux: Ring buffer overflow, discarding oldest data 
(%02X)\n",
+                       (int)rbuf->rb_buf[pos]
+                       );
+               rbuf->rb_start = (rbuf->rb_start + 1) % RING_BUF_SIZE;
+       } else
+               ++rbuf->rb_length;
+       rbuf->rb_buf[pos] = data;
+}
+
+static __inline bool
+rbuf_empty(struct ring_buffer * rbuf)
+{
+       return rbuf->rb_length == 0;
+}
+
+static int
+psaux_match(device_t parent, cfdata_t match, void *aux)
+{
+       struct pckbport_attach_args *pa = aux;
+       u_char cmd[1], resp[2];
+       int res;
+
+       if (pa->pa_slot != PCKBPORT_AUX_SLOT)
+               return 0;
+       pckbport_flush(pa->pa_tag, pa->pa_slot);
+
+       /*reset*/
+       cmd[0] = PMS_RESET;
+       res = pckbport_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 2, resp, 1);
+       if (res)
+               return 0;
+       if (resp[0] != PMS_RSTDONE)
+               return 0;
+       if (resp[1] != 0) /*not mouse*/
+               return 0;
+       printf("psaux: attached\n");
+       return 10;
+}
+
+static int
+psaux_open(dev_t dev, int flags, int mode, struct lwp *l)
+{
+       struct psaux_softc *sc = device_lookup_private(&psaux_cd, minor(dev));
+       psaux_enable(sc);
+       return (0);
+}
+
+static int
+psaux_close(dev_t dev, int flags, int mode,
+    struct lwp *l)
+{
+       struct psaux_softc *sc = device_lookup_private(&psaux_cd, minor(dev));
+       psaux_disable(sc);
+       return (0);
+}
+
+static int
+psaux_read(dev_t dev, struct uio *uio, int flags)
+{
+       struct psaux_softc *sc = device_lookup_private(&psaux_cd, minor(dev));
+       int err, ret = -1;
+       size_t copied;
+       unsigned char res_buf[RING_BUF_SIZE];
+       mutex_enter(&sc->sc_lock);
+       if (sc->sc_closing) {
+               ret = ENXIO;
+               goto out_unlock;
+       }
+       while (rbuf_empty(&sc->sc_rbuf)) {
+               if (flags & IO_NDELAY) {
+                       ret = EWOULDBLOCK;
+                       goto out_unlock;
+               }
+               err = cv_wait_sig(&sc->sc_cond, &sc->sc_lock);
+               if (err) {
+                       ret = err;
+                       goto out_unlock;
+               }
+       }
+       if (sc->sc_closing) {
+               ret = ENXIO;
+               goto out_unlock;
+       }
+       copied = rbuf_drain(
+               &sc->sc_rbuf,
+               res_buf,
+               min(uio->uio_resid, RING_BUF_SIZE)
+               );
+       ret = 0;
+out_unlock:
+       mutex_exit(&sc->sc_lock);
+       if (ret == 0) {
+               ret = uiomove(res_buf, copied, uio);
+               if (ret)
+                       DPRINTF("pasuax: uiomove error: %d\n", err);
+       }
+       return ret;
+}
+
+static int
+psaux_write(dev_t dev, struct uio *uio, int flags)
+{
+       int ret;
+       struct psaux_softc *sc = device_lookup_private(&psaux_cd, minor(dev));
+       while (uio->uio_resid) {
+               u_char c;
+               if (uiomove(&c, 1, uio))
+                       return EFAULT;
+               mutex_enter(&sc->sc_lock);
+               //quite ugly, but we have to omit the automatic ACK handling
+               ret = sc->sc_kbctag->t_ops->t_send_devcmd(
+                       sc->sc_kbctag->t_cookie,
+                       sc->sc_kbcslot,
+                       c
+                       );
+               mutex_exit(&sc->sc_lock);
+               if (!ret) {
+                       DPRINTF("psaux: write error: %d\n", ret);
+                       return EIO;
+               }
+               
+       }
+       return 0;
+}
+
+
+static int
+psaux_poll(dev_t dev, int events, struct lwp *l)
+{
+       struct psaux_softc *sc = device_lookup_private(&psaux_cd, minor(dev));
+       int revents = events & (POLLOUT | POLLWRNORM);
+       mutex_enter(&sc->sc_lock);
+       if (!rbuf_empty(&sc->sc_rbuf))
+               revents |= events & (POLLIN | POLLRDNORM);
+       else
+               selrecord(curlwp, &sc->sc_sel);
+       mutex_exit(&sc->sc_lock);
+       return revents;
+}
+
+static void
+psaux_attach(device_t parent, device_t self, void *aux)
+{
+       struct psaux_softc *sc = device_private(self);
+       struct pckbport_attach_args *pa = aux;
+       u_char cmd[2], resp[2];
+       int res;
+
+       sc->sc_dev = self;
+       sc->sc_kbctag = pa->pa_tag;
+       sc->sc_kbcslot = pa->pa_slot;
+       sc->sc_closing = 0;
+       rbuf_init(&sc->sc_rbuf);
+       mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_TTY);
+       cv_init(&sc->sc_cond, "psaux");
+       selinit(&sc->sc_sel);
+
+       /* Flush any garbage. */
+       pckbport_flush(pa->pa_tag, pa->pa_slot);
+
+       /* reset the device */
+       cmd[0] = PMS_RESET;
+       res = pckbport_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 2, resp, 1);
+
+       /* Install generic handler. */
+       pckbport_set_inputhandler(sc->sc_kbctag, sc->sc_kbcslot,
+               psaux_input, sc, device_xname(sc->sc_dev));
+
+       /* no interrupts until enabled */
+       cmd[0] = PMS_DEV_DISABLE;
+       res = pckbport_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 0, 0, 0);
+       if (res)
+               aprint_error("psauxattach: disable error\n");
+       pckbport_slot_enable(sc->sc_kbctag, sc->sc_kbcslot, 0);
+       if (!pmf_device_register(self, psaux_suspend, psaux_resume))
+               aprint_error_dev(self, "couldn't establish power handler\n");
+}
+
+static void
+do_enable(struct psaux_softc *sc)
+{
+       u_char cmd[1];
+       int res;
+
+       pckbport_slot_enable(sc->sc_kbctag, sc->sc_kbcslot, 1);
+
+       cmd[0] = PMS_DEV_ENABLE;
+       res = pckbport_enqueue_cmd(sc->sc_kbctag, sc->sc_kbcslot, cmd,
+           1, 0, 1, 0);
+       if (res)
+               aprint_error("psaux_enable: command error %d\n", res);
+
+}
+
+static void
+do_disable(struct psaux_softc *sc)
+{
+       u_char cmd[1];
+       int res;
+
+       cmd[0] = PMS_DEV_DISABLE;
+       res = pckbport_enqueue_cmd(sc->sc_kbctag, sc->sc_kbcslot, cmd,
+           1, 0, 1, 0);
+       if (res)
+               aprint_error("psaux_disable: command error\n");
+
+       pckbport_slot_enable(sc->sc_kbctag, sc->sc_kbcslot, 0);
+}
+
+static int
+psaux_enable(void *v)
+{
+       struct psaux_softc *sc = v;
+
+       if (sc->sc_enabled)
+               return EBUSY;
+
+       do_enable(sc);
+
+       mutex_enter(&sc->sc_lock);
+       sc->sc_enabled = 1;
+       mutex_exit(&sc->sc_lock);
+
+       return 0;
+}
+
+static void
+psaux_disable(void *v)
+{
+       struct psaux_softc *sc = v;
+
+       do_disable(sc);
+
+       mutex_enter(&sc->sc_lock);
+       sc->sc_enabled = 0;
+       mutex_exit(&sc->sc_lock);
+}
+
+static bool
+psaux_suspend(device_t dv PMF_FN_ARGS)
+{
+       struct psaux_softc *sc = device_private(dv);
+
+       if (sc->sc_enabled)
+               do_disable(sc);
+
+       return true;
+}
+
+static bool
+psaux_resume(device_t dv PMF_FN_ARGS)
+{
+       struct psaux_softc *sc = device_private(dv);
+
+       if (sc->sc_enabled)
+               do_enable(sc); /* only if we were suspended */
+
+       return true;
+}
+
+static void
+psaux_input(void *vsc, int data)
+{
+       struct psaux_softc *sc = vsc;
+
+       if (!sc->sc_enabled)
+               /* Interrupts are not expected.  Discard the byte. */
+               return;
+       if (data & (~0xff))
+               DPRINTF("psaux: got data bigger than one byte: %02X\n", data);
+       
+       /* now we can add it to the buffer */
+       mutex_enter(&sc->sc_lock);
+       rbuf_add(&sc->sc_rbuf, (unsigned char)data);
+       cv_signal(&sc->sc_cond);
+       selnotify(&sc->sc_sel, 0, 0);
+       mutex_exit(&sc->sc_lock);
+}
+


Home | Main Index | Thread Index | Old Index