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 ma...@dopiera.pl
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); +} +