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