Subject: Re: kern/12132 (wsmouse emulate3button patch)
To: None <gnats-bugs@netbsd.org>
From: YAMAMOTO Takashi <yamt@mwd.biglobe.ne.jp>
List: netbsd-bugs
Date: 02/07/2006 07:57:10
--NextPart-20060207075223-0364900
Content-Type: Text/Plain; charset=us-ascii
> Synopsis: wsmouse emulate3button patch
i digged a patch which seems newer than the one in the PR. (attached)
no idea which is better, tho. :-)
YAMAMOTO Takashi
--NextPart-20060207075223-0364900
Content-Type: Text/Plain; charset=us-ascii
Content-Disposition: attachment; filename="emu3btn.diff"
Index: wsconsio.h
===================================================================
RCS file: /cvsroot/src/sys/dev/wscons/wsconsio.h,v
retrieving revision 1.76
diff -u -p -r1.76 wsconsio.h
--- wsconsio.h 23 Nov 2005 09:38:02 -0000 1.76
+++ wsconsio.h 27 Nov 2005 23:14:45 -0000
@@ -241,6 +241,27 @@ struct wsmouse_id {
};
#define WSMOUSEIO_GETID _IOWR('W', 38, struct wsmouse_id)
+/* set/get emulate3button mask. 0 means no emulation */
+#define WSMOUSEIO_SEMU3BTN_MASK _IOW('W', 58, u_int)
+#define WSMOUSEIO_GEMU3BTN_MASK _IOR('W', 59, u_int)
+#define WSMOUSE_EMU3BTN_MASK_MIN 0
+#define WSMOUSE_EMU3BTN_MASK_DEFAULT 0
+#define WSMOUSE_EMU3BTN_MASK_MAX 0xffff
+
+/* set/get emulate3button button. */
+#define WSMOUSEIO_SEMU3BTN_BTN _IOW('W', 60, u_int)
+#define WSMOUSEIO_GEMU3BTN_BTN _IOR('W', 61, u_int)
+#define WSMOUSE_EMU3BTN_BTN_MIN 0
+#define WSMOUSE_EMU3BTN_BTN_DEFAULT 1 /* middle button */
+#define WSMOUSE_EMU3BTN_BTN_MAX 31
+
+/* set/get emulate3button timeout. */
+#define WSMOUSEIO_SEMU3BTN_TIMEOUT _IOW('W', 62, u_int)
+#define WSMOUSEIO_GEMU3BTN_TIMEOUT _IOR('W', 63, u_int)
+#define WSMOUSE_EMU3BTN_TIMEOUT_MIN 0
+#define WSMOUSE_EMU3BTN_TIMEOUT_DEFAULT 100
+#define WSMOUSE_EMU3BTN_TIMEOUT_MAX 500
+
/*
* Display ioctls (64 - 95)
*/
Index: wsevent.c
===================================================================
RCS file: /cvsroot/src/sys/dev/wscons/wsevent.c,v
retrieving revision 1.16
diff -u -p -r1.16 wsevent.c
--- wsevent.c 7 Aug 2003 16:31:29 -0000 1.16
+++ wsevent.c 27 Nov 2005 23:14:45 -0000
@@ -85,6 +85,9 @@ __KERNEL_RCSID(0, "$NetBSD: wsevent.c,v
#include <sys/vnode.h>
#include <sys/select.h>
#include <sys/poll.h>
+#include <sys/syslog.h>
+#include <sys/kernel.h>
+#include <sys/time.h>
#include <dev/wscons/wsconsio.h>
#include <dev/wscons/wseventvar.h>
@@ -199,6 +202,40 @@ wsevent_poll(struct wseventvar *ev, int
return (revents);
}
+/*
+ * return -1 if can't enqueue (full of queue)
+ */
+int
+wsevent_write(struct wseventvar* evar, u_int type, int value)
+{
+ int put;
+ struct wscons_event* ev;
+ int s;
+
+ put = evar->put;
+ ev = &evar->q[put];
+
+ put = (put + 1) % WSEVENT_QSIZE;
+ if (put == evar->get) {
+ static struct timeval last;
+ struct timeval interval = {5, 0};
+ if (ratecheck(&last, &interval))
+ log(LOG_WARNING, "wscons event queue overflow\n");
+ return -1;
+ }
+
+ ev->type = type;
+ ev->value = value;
+
+ s = splhigh();
+ TIMEVAL_TO_TIMESPEC(&time, &ev->time);
+ splx(s);
+
+ evar->put = put;
+
+ return 0;
+}
+
static void
filt_wseventrdetach(struct knote *kn)
{
Index: wseventvar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/wscons/wseventvar.h,v
retrieving revision 1.8
diff -u -p -r1.8 wseventvar.h
--- wseventvar.h 7 Aug 2003 16:31:29 -0000 1.8
+++ wseventvar.h 27 Nov 2005 23:14:45 -0000
@@ -105,6 +105,7 @@ void wsevent_init(struct wseventvar *);
void wsevent_fini(struct wseventvar *);
int wsevent_read(struct wseventvar *, struct uio *, int);
int wsevent_poll(struct wseventvar *, int, struct proc *);
+int wsevent_write(struct wseventvar *, u_int, int);
int wsevent_kqfilter(struct wseventvar *ev, struct knote *kn);
/*
Index: wsmouse.c
===================================================================
RCS file: /cvsroot/src/sys/dev/wscons/wsmouse.c,v
retrieving revision 1.37
diff -u -p -r1.37 wsmouse.c
--- wsmouse.c 23 Nov 2005 09:38:02 -0000 1.37
+++ wsmouse.c 27 Nov 2005 23:14:46 -0000
@@ -73,6 +73,10 @@
/*
* Mouse driver.
*/
+#if 1
+#define WSMOUSE_EMULATE3BUTTON
+/*#define WSMOUSE_DEBUG*/
+#endif
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: wsmouse.c,v 1.37 2005/11/23 09:38:02 augustss Exp $");
@@ -94,6 +98,9 @@ __KERNEL_RCSID(0, "$NetBSD: wsmouse.c,v
#include <sys/signalvar.h>
#include <sys/device.h>
#include <sys/vnode.h>
+#ifdef WSMOUSE_EMULATE3BUTTON
+#include <sys/callout.h>
+#endif
#include <dev/wscons/wsconsio.h>
#include <dev/wscons/wsmousevar.h>
@@ -132,6 +139,15 @@ struct wsmouse_softc {
int sc_refcnt;
u_char sc_dying; /* device is being detached */
+
+#ifdef WSMOUSE_EMULATE3BUTTON
+ struct callout sc_emu3btn_callout;
+ u_int sc_delayed_event;
+ u_int sc_emu3btn_mask;
+ u_int sc_emu3btn_btn;
+ u_int sc_emu3btn_timeout;
+ u_char sc_emulating;
+#endif
};
static int wsmouse_match(struct device *, struct cfdata *, void *);
@@ -149,6 +165,11 @@ static int wsmouse_mux_close(struct wse
static int wsmousedoioctl(struct device *, u_long, caddr_t, int, struct proc *);
+static int wsmouse_input_button(struct wsmouse_softc *, u_int);
+#ifdef WSMOUSE_EMULATE3BUTTON
+static void establish_delayed_event(struct wsmouse_softc *);
+static void wsmouse_emu3btn_callout(void *);
+#endif
static int wsmousedoopen(struct wsmouse_softc *, struct wseventvar *);
CFATTACH_DECL(wsmouse, sizeof (struct wsmouse_softc),
@@ -175,6 +196,39 @@ struct wssrcops wsmouse_srcops = {
};
#endif
+#ifdef WSMOUSE_EMULATE3BUTTON
+static void
+establish_delayed_event(struct wsmouse_softc* sc)
+{
+ u_int d, mb;
+/*
+ if (sc->sc_delayed_event == 0) {
+ DPRINTF(("wsmouse: no delayed events to establish\n"));
+ }
+ else {
+*/
+ DPRINTF(("wsmouse: establish delayed event(%x)\n", sc->sc_delayed_event));
+ d = sc->sc_delayed_event;
+ sc->sc_delayed_event = 0;
+ mb = sc->sc_ub ^ d;
+ wsmouse_input_button(sc, mb);
+/*
+ }
+*/
+}
+
+static void
+wsmouse_emu3btn_callout(void *arg)
+{
+ int s;
+
+ DPRINTF(("wsmouse: callout\n"));
+ s = spltty();
+ establish_delayed_event((struct wsmouse_softc*)arg);
+ splx(s);
+}
+#endif
+
/*
* Print function (for parent devices).
*/
@@ -205,6 +259,15 @@ wsmouse_attach(struct device *parent, st
sc->sc_accessops = ap->accessops;
sc->sc_accesscookie = ap->accesscookie;
+#ifdef WSMOUSE_EMULATE3BUTTON
+ sc->sc_delayed_event = 0;
+ sc->sc_emu3btn_mask = WSMOUSE_EMU3BTN_MASK_DEFAULT;
+ sc->sc_emu3btn_btn = WSMOUSE_EMU3BTN_BTN_DEFAULT;
+ sc->sc_emu3btn_timeout = WSMOUSE_EMU3BTN_TIMEOUT_DEFAULT;
+ sc->sc_emulating = 0;
+ callout_init(&sc->sc_emu3btn_callout);
+#endif
+
#if NWSMUX > 0
sc->sc_base.me_ops = &wsmouse_srcops;
mux = sc->sc_base.me_dv.dv_cfdata->wsmousedevcf_mux;
@@ -289,10 +352,15 @@ wsmouse_input_xyzw(struct device *wsmous
int x, int y, int z, int w, u_int flags)
{
struct wsmouse_softc *sc = (struct wsmouse_softc *)wsmousedev;
- struct wscons_event *ev;
struct wseventvar *evar;
- int mb, ub, d, get, put, any;
+ int any;
+ u_int mb;
+#ifdef WSMOUSE_EMULATE3BUTTON
+ u_int d, ub;
+ int emu3btn_mask;
+ int emu3btn_btn;
+#endif
/*
* Discard input if not open.
*/
@@ -329,89 +397,56 @@ wsmouse_input_xyzw(struct device *wsmous
* of changes or out of room. As events get delivered,
* mark them `unchanged'.
*/
- ub = sc->sc_ub;
any = 0;
- get = evar->get;
- put = evar->put;
- ev = &evar->q[put];
-
- /* NEXT prepares to put the next event, backing off if necessary */
-#define NEXT \
- if ((++put) % WSEVENT_QSIZE == get) { \
- put--; \
- goto out; \
- }
- /* ADVANCE completes the `put' of the event */
-#define ADVANCE \
- ev++; \
- if (put >= WSEVENT_QSIZE) { \
- put = 0; \
- ev = &evar->q[0]; \
- } \
- any = 1
- /* TIMESTAMP sets `time' field of the event to the current time */
-#define TIMESTAMP \
- do { \
- int s; \
- s = splhigh(); \
- TIMEVAL_TO_TIMESPEC(&time, &ev->time); \
- splx(s); \
- } while (0)
if (flags & WSMOUSE_INPUT_ABSOLUTE_X) {
if (sc->sc_x != x) {
- NEXT;
- ev->type = WSCONS_EVENT_MOUSE_ABSOLUTE_X;
- ev->value = x;
- TIMESTAMP;
- ADVANCE;
+ if (wsevent_write(evar, WSCONS_EVENT_MOUSE_ABSOLUTE_X, x)) {
+ goto out;
+ }
+ any = 1;
sc->sc_x = x;
}
} else {
if (sc->sc_dx) {
- NEXT;
- ev->type = WSCONS_EVENT_MOUSE_DELTA_X;
- ev->value = sc->sc_dx;
- TIMESTAMP;
- ADVANCE;
+ if (wsevent_write(evar, WSCONS_EVENT_MOUSE_DELTA_X, sc->sc_dx)) {
+ goto out;
+ }
+ any = 1;
sc->sc_dx = 0;
}
}
if (flags & WSMOUSE_INPUT_ABSOLUTE_Y) {
if (sc->sc_y != y) {
- NEXT;
- ev->type = WSCONS_EVENT_MOUSE_ABSOLUTE_Y;
- ev->value = y;
- TIMESTAMP;
- ADVANCE;
+ if (wsevent_write(evar, WSCONS_EVENT_MOUSE_ABSOLUTE_Y, y)) {
+ goto out;
+ }
+ any = 1;
sc->sc_y = y;
}
} else {
if (sc->sc_dy) {
- NEXT;
- ev->type = WSCONS_EVENT_MOUSE_DELTA_Y;
- ev->value = sc->sc_dy;
- TIMESTAMP;
- ADVANCE;
+ if (wsevent_write(evar, WSCONS_EVENT_MOUSE_DELTA_Y, sc->sc_dy)) {
+ goto out;
+ }
+ any = 1;
sc->sc_dy = 0;
}
}
if (flags & WSMOUSE_INPUT_ABSOLUTE_Z) {
if (sc->sc_z != z) {
- NEXT;
- ev->type = WSCONS_EVENT_MOUSE_ABSOLUTE_Z;
- ev->value = z;
- TIMESTAMP;
- ADVANCE;
+ if (wsevent_write(evar, WSCONS_EVENT_MOUSE_ABSOLUTE_Z, z)) {
+ goto out;
+ }
+ any = 1;
sc->sc_z = z;
}
} else {
if (sc->sc_dz) {
- NEXT;
- ev->type = WSCONS_EVENT_MOUSE_DELTA_Z;
- ev->value = sc->sc_dz;
- TIMESTAMP;
- ADVANCE;
+ if (wsevent_write(evar, WSCONS_EVENT_MOUSE_DELTA_Z, sc->sc_dz)) {
+ goto out;
+ }
+ any = 1;
sc->sc_dz = 0;
}
}
@@ -436,27 +471,67 @@ wsmouse_input_xyzw(struct device *wsmous
}
mb = sc->sc_mb;
- while ((d = mb ^ ub) != 0) {
- /*
- * Mouse button change. Find the first change and drop
- * it into the event queue.
- */
- NEXT;
- ev->value = ffs(d) - 1;
- KASSERT(ev->value >= 0);
+#ifdef WSMOUSE_EMULATE3BUTTON
+ ub = sc->sc_ub ^ sc->sc_delayed_event;
+ emu3btn_mask = sc->sc_emu3btn_mask;
+ emu3btn_btn = sc->sc_emu3btn_btn;
+ if ((d = (mb ^ ub) & emu3btn_mask) != 0) {
+ if ((mb & emu3btn_mask) == emu3btn_mask
+ && (sc->sc_delayed_event || sc->sc_emulating || d == emu3btn_mask)) {
+ /* emulate press */
+ sc->sc_delayed_event = 0; /* clear delayed event */
+ sc->sc_emulating = 1; /* start emulating */
+ DPRINTF(("wsmouse: start emulating\n"));
+ if (wsevent_write(evar, WSCONS_EVENT_MOUSE_DOWN, emu3btn_btn)) {
+ goto out;
+ }
+ any = 1;
+ DPRINTF(("wsmouse: emu3btn down\n"));
+ }
+ else if ((ub & emu3btn_mask) == emu3btn_mask && sc->sc_emulating) {
+ /* emulate release */
+ if (wsevent_write(evar, WSCONS_EVENT_MOUSE_UP, emu3btn_btn)) {
+ goto out;
+ }
+ any = 1;
+ DPRINTF(("wsmouse: emu3btn up\n"));
+ }
+ else {
+ establish_delayed_event(sc);
- d = 1 << ev->value;
- ev->type =
- (mb & d) ? WSCONS_EVENT_MOUSE_DOWN : WSCONS_EVENT_MOUSE_UP;
- TIMESTAMP;
- ADVANCE;
- ub ^= d;
+ /*
+ * if emulating == 0, press event is delayed.
+ */
+ if (sc->sc_emulating == 0 && d & mb) {
+ /*
+ * delay event
+ */
+ sc->sc_delayed_event ^= d;
+ DPRINTF(("wsmouse: set callout delay_ev= %u ub=%u mb=%u\n", d, ub, mb));
+ callout_reset(&sc->sc_emu3btn_callout, hz*sc->sc_emu3btn_timeout/1000,
+ wsmouse_emu3btn_callout, (void*)sc);
+ }
+ }
+ }
+
+ mb ^= sc->sc_delayed_event; /* restrict button events for delayed event */
+
+#endif
+
+ if (wsmouse_input_button(sc, mb) > 0) {
+ any = 1;
+ }
+
+#ifdef WSMOUSE_EMULATE3BUTTON
+ if (sc->sc_emulating && (sc->sc_ub & sc->sc_emu3btn_mask) == 0) {
+ sc->sc_emulating = 0;
+ DPRINTF(("wsmouse: end emulating\n"));
}
+#endif
+
out:
if (any) {
- sc->sc_ub = ub;
- evar->put = put;
WSEVENT_WAKEUP(evar);
#if NWSMUX > 0
DPRINTFN(5,("wsmouse_input: %s wakeup evar=%p\n",
@@ -465,6 +540,54 @@ out:
}
}
+/*
+ * return num of enqueued events
+ */
+static int
+wsmouse_input_button(struct wsmouse_softc* sc, u_int mb)
+{
+ struct wseventvar* evar;
+ u_int d;
+ u_int ub;
+ int count = 0;
+
+ evar = sc->sc_base.me_evp;
+
+ ub = sc->sc_ub;
+
+ while ((d = mb ^ ub) != 0) {
+ /*
+ * Mouse button change. Find the first change and drop
+ * it into the event queue.
+ */
+ u_int type;
+ int value;
+
+ type = (mb & d) ? WSCONS_EVENT_MOUSE_DOWN : WSCONS_EVENT_MOUSE_UP;
+ value = ffs(d) - 1;
+ KASSERT(value >= 0);
+ d = 1 << value;
+
+#ifdef WSMOUSE_EMULATE3BUTTON
+ if (sc->sc_emulating == 0 || (d & sc->sc_emu3btn_mask) == 0) {
+#endif
+ if (wsevent_write(evar, type, value)) {
+ break;
+ }
+ count ++;
+ DPRINTF(("wsmouse: event: ub %u->%u\n", ub, ub^d));
+#ifdef WSMOUSE_EMULATE3BUTTON
+ }
+#endif
+
+ ub ^= d;
+ }
+
+ sc->sc_ub = ub;
+
+ return count;
+}
+
int
wsmouseopen(dev_t dev, int flags, int mode, struct proc *p)
{
@@ -589,6 +712,10 @@ wsmouse_do_ioctl(struct wsmouse_softc *s
{
int error;
+#ifdef WSMOUSE_EMULATE3BUTTON
+ u_int count, t;
+#endif
+
if (sc->sc_dying)
return (EIO);
@@ -619,6 +746,57 @@ wsmouse_do_ioctl(struct wsmouse_softc *s
if (*(int *)data != sc->sc_base.me_evp->io->p_pgid)
return (EPERM);
return (0);
+
+#ifdef WSMOUSE_EMULATE3BUTTON
+ /*
+ * do emulate 3 button things
+ */
+ case WSMOUSEIO_SEMU3BTN_MASK:
+ t = (uint)*(int*)data;
+ if (t > WSMOUSE_EMU3BTN_MASK_MAX)
+ return (EINVAL);
+
+ /*
+ * count bits
+ */
+ count = 0;
+ for (; t; t &= t-1) {
+ count++;
+ }
+ /*
+ * more than 2 buttons are not supported.
+ */
+ if (count > 2) {
+ return (EINVAL);
+ }
+
+ sc->sc_emu3btn_mask = *(int*)data;
+ return (0);
+
+ case WSMOUSEIO_GEMU3BTN_MASK:
+ *(int*)data = sc->sc_emu3btn_mask;
+ return (0);
+
+ case WSMOUSEIO_SEMU3BTN_BTN:
+ if ((u_int)*(int*)data > WSMOUSE_EMU3BTN_BTN_MAX)
+ return (EINVAL);
+ sc->sc_emu3btn_btn = *(int*)data;
+ return (0);
+
+ case WSMOUSEIO_GEMU3BTN_BTN:
+ *(int*)data = sc->sc_emu3btn_btn;
+ return (0);
+
+ case WSMOUSEIO_SEMU3BTN_TIMEOUT:
+ if ((u_int)*(int*)data > WSMOUSE_EMU3BTN_TIMEOUT_MAX)
+ return (EINVAL);
+ sc->sc_emu3btn_timeout = *(int*)data;
+ return (0);
+
+ case WSMOUSEIO_GEMU3BTN_TIMEOUT:
+ *(int*)data = sc->sc_emu3btn_timeout;
+ return (0);
+#endif
}
/*
--NextPart-20060207075223-0364900--